diff --git a/build/.nativeignore b/build/.nativeignore deleted file mode 100644 index a04b4dbc23..0000000000 --- a/build/.nativeignore +++ /dev/null @@ -1,126 +0,0 @@ -# cleanup rules for native node modules, .gitignore style - -fsevents/binding.gyp -fsevents/fsevents.cc -fsevents/build/** -fsevents/src/** -fsevents/test/** -!fsevents/**/*.node - -vscode-sqlite3/binding.gyp -vscode-sqlite3/benchmark/** -vscode-sqlite3/cloudformation/** -vscode-sqlite3/deps/** -vscode-sqlite3/test/** -vscode-sqlite3/build/** -vscode-sqlite3/src/** -!vscode-sqlite3/build/Release/*.node - -oniguruma/binding.gyp -oniguruma/build/** -oniguruma/src/** -oniguruma/deps/** -!oniguruma/build/Release/*.node -!oniguruma/src/*.js - -windows-mutex/binding.gyp -windows-mutex/build/** -windows-mutex/src/** -!windows-mutex/**/*.node - -native-keymap/binding.gyp -native-keymap/build/** -native-keymap/src/** -native-keymap/deps/** -!native-keymap/build/Release/*.node - -native-is-elevated/binding.gyp -native-is-elevated/build/** -native-is-elevated/src/** -native-is-elevated/deps/** -!native-is-elevated/build/Release/*.node - -native-watchdog/binding.gyp -native-watchdog/build/** -native-watchdog/src/** -!native-watchdog/build/Release/*.node - -spdlog/binding.gyp -spdlog/build/** -spdlog/deps/** -spdlog/src/** -spdlog/test/** -!spdlog/build/Release/*.node - -jschardet/dist/** - -windows-foreground-love/binding.gyp -windows-foreground-love/build/** -windows-foreground-love/src/** -!windows-foreground-love/**/*.node - -windows-process-tree/binding.gyp -windows-process-tree/build/** -windows-process-tree/src/** -!windows-process-tree/**/*.node - -gc-signals/binding.gyp -gc-signals/build/** -gc-signals/src/** -gc-signals/deps/** - -!gc-signals/build/Release/*.node -!gc-signals/src/index.js - -keytar/binding.gyp -keytar/build/** -keytar/src/** -keytar/script/** -keytar/node_modules/** -!keytar/**/*.node - -node-pty/binding.gyp -node-pty/build/** -node-pty/src/** -node-pty/tools/** -!node-pty/build/Release/*.exe -!node-pty/build/Release/*.dll -!node-pty/build/Release/*.node - -chart.js/node_modules/** - -emmet/node_modules/** - -pty.js/build/** -!pty.js/build/Release/** - -jquery-ui/external/** -jquery-ui/demos/** - -core-js/**/** - -slickgrid/node_modules/** -slickgrid/examples/** - -vscode-nsfw/binding.gyp -vscode-nsfw/build/** -vscode-nsfw/src/** -vscode-nsfw/openpa/** -vscode-nsfw/includes/** -!vscode-nsfw/build/Release/*.node -!vscode-nsfw/**/*.a - -vsda/binding.gyp -vsda/README.md -vsda/build/** -vsda/*.bat -vsda/*.sh -vsda/*.cpp -vsda/*.h -!vsda/build/Release/vsda.node - -vscode-windows-ca-certs/**/* -!vscode-windows-ca-certs/package.json -!vscode-windows-ca-certs/**/*.node - -node-addon-api/**/* \ No newline at end of file diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 5d6ec8c2cf..f5d5ef626b 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -7,21 +7,15 @@ steps: inputs: versionSpec: "1.10.1" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - script: | set -e cat << EOF > ~/.netrc machine monacotools.visualstudio.com - password $(devops-pat) + password $(VSO_PAT) machine github.com login vscode - password $(github-distro-mixin-password) + password $(VSCODE_MIXIN_PASSWORD) EOF git config user.email "vscode@microsoft.com" @@ -40,8 +34,8 @@ steps: - script: | set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ + AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ ./build/azure-pipelines/darwin/build.sh displayName: Build @@ -83,11 +77,11 @@ steps: - script: | set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ + AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ + VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ ./build/azure-pipelines/darwin/publish.sh displayName: Publish diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index 639456ad4c..dc55bce808 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -10,19 +10,13 @@ steps: inputs: versionSpec: "10.15.1" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - script: | set -e cat << EOF > ~/.netrc machine github.com login vscode - password $(github-distro-mixin-password) + password $(VSCODE_MIXIN_PASSWORD) EOF git config user.email "vscode@microsoft.com" diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index f727e30d25..342d72e496 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -7,12 +7,6 @@ steps: inputs: versionSpec: "1.10.1" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - script: | set -e export npm_config_arch="$(VSCODE_ARCH)" @@ -22,10 +16,10 @@ steps: cat << EOF > ~/.netrc machine monacotools.visualstudio.com - password $(devops-pat) + password $(VSO_PAT) machine github.com login vscode - password $(github-distro-mixin-password) + password $(VSCODE_MIXIN_PASSWORD) EOF git config user.email "vscode@microsoft.com" @@ -44,7 +38,7 @@ steps: - script: | set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ ./build/azure-pipelines/linux/build.sh displayName: Build @@ -61,10 +55,10 @@ steps: - script: | set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ + VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ + VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ ./build/azure-pipelines/linux/publish.sh displayName: Publish diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 9d98e9fa47..9588ebcb36 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -7,12 +7,6 @@ steps: inputs: versionSpec: "1.10.1" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact' inputs: @@ -50,6 +44,6 @@ steps: (cd $SNAP_ROOT/code-* && sudo snapcraft snap --output "$SNAP_PATH") # Publish snap package - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index c8bedfbffc..86868f6a2a 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -1,11 +1,9 @@ resources: containers: - container: vscode-x64 - endpoint: VSCodeHub - image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 + image: joaomoreno/vscode-linux-build-agent:x64 - container: vscode-ia32 - endpoint: VSCodeHub - image: vscodehub.azurecr.io/vscode-linux-build-agent:ia32 + image: joaomoreno/vscode-linux-build-agent:ia32 - container: snapcraft image: snapcore/snapcraft diff --git a/build/azure-pipelines/sync-mooncake.yml b/build/azure-pipelines/sync-mooncake.yml index f3e8bc0785..c422839de1 100644 --- a/build/azure-pipelines/sync-mooncake.yml +++ b/build/azure-pipelines/sync-mooncake.yml @@ -7,18 +7,12 @@ steps: inputs: versionSpec: "1.10.1" -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - script: | set -e (cd build ; yarn) - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - MOONCAKE_STORAGE_ACCESS_KEY="$(vscode-mooncake-storage-key)" \ + 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" diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 8a6a6abb65..a49349150d 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -12,16 +12,10 @@ steps: versionSpec: '2.x' addToPath: true -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - "machine monacotools.visualstudio.com`npassword $(devops-pat)`nmachine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII + "machine monacotools.visualstudio.com`npassword $(VSO_PAT)`nmachine github.com`nlogin vscode`npassword $(VSCODE_MIXIN_PASSWORD)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII $env:npm_config_arch="$(VSCODE_ARCH)" $env:CHILD_CONCURRENCY="1" @@ -42,7 +36,7 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + $env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" .\build\azure-pipelines\win32\build.ps1 displayName: Build @@ -132,15 +126,15 @@ steps: - powershell: | $ErrorActionPreference = "Stop" - .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(esrp-auth-certificate) -AuthCertificateKey $(esrp-auth-certificate-key) + .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(ESRP_AUTH_CERTIFICATE) -AuthCertificateKey $(ESRP_AUTH_CERTIFICATE_KEY) displayName: Import ESRP Auth Certificate - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" - $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" - $env:VSCODE_HOCKEYAPP_TOKEN = "$(vscode-hockeyapp-token)" + $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)" + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)" + $env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)" .\build\azure-pipelines\win32\publish.ps1 displayName: Publish diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 4754f6eee0..c988384009 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -335,7 +335,33 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const deps = gulp.src(depsSrc, { base: '.', dot: true }) .pipe(filter(['**', '!**/package-lock.json'])) - .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))) + .pipe(util.cleanNodeModule('fsevents', ['binding.gyp', 'fsevents.cc', 'build/**', 'src/**', 'test/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('vscode-sqlite3', ['binding.gyp', 'benchmark/**', 'cloudformation/**', 'deps/**', 'test/**', 'build/**', 'src/**'], ['build/Release/*.node'])) + .pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/*.js'])) + .pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node'])) + .pipe(util.cleanNodeModule('native-is-elevated', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node'])) + .pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['build/Release/*.node'])) + .pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['build/Release/*.node'])) + .pipe(util.cleanNodeModule('jschardet', ['dist/**'])) + .pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/index.js'])) + .pipe(util.cleanNodeModule('keytar', ['binding.gyp', 'build/**', 'src/**', 'script/**', 'node_modules/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node'])) + // {{SQL CARBON EDIT}} + .pipe(util.cleanNodeModule('chart.js', ['node_modules/**'], undefined)) + .pipe(util.cleanNodeModule('emmet', ['node_modules/**'], undefined)) + .pipe(util.cleanNodeModule('pty.js', ['build/**'], ['build/Release/**'])) + .pipe(util.cleanNodeModule('jquery-ui', ['external/**', 'demos/**'], undefined)) + .pipe(util.cleanNodeModule('core-js', ['**/**'], undefined)) + .pipe(util.cleanNodeModule('slickgrid', ['node_modules/**', 'examples/**'], undefined)) + .pipe(util.cleanNodeModule('nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['**/*.node', '**/*.a'])) + .pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a'])) + // {{SQL CARBON EDIT}} - End + .pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node'])) + .pipe(util.cleanNodeModule('vscode-windows-ca-certs', ['**/*'], ['package.json', '**/*.node'])) + .pipe(util.cleanNodeModule('node-addon-api', ['**/*'])) .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar')); // {{SQL CARBON EDIT}} @@ -354,7 +380,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op ], { base: '.', dot: true }); let all = es.merge( - packageJsonStream, + packageJsonStream, productJsonStream, license, api, diff --git a/build/lib/extensions.js b/build/lib/extensions.js index b16f7cad4a..250be3f063 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -306,7 +306,9 @@ function packageExtensionsStream(optsIn) { ..._.flatten(extensionsProductionDependencies.map((d) => path.relative(root, d.path)).map((d) => [`${d}/**`, `!${d}/**/{test,tests}/**`])), ]; const localExtensionDependencies = () => gulp.src(extensionDepsSrc, { base: '.', dot: true }) - .pipe(filter(['**', '!**/package-lock.json'])); + .pipe(filter(['**', '!**/package-lock.json'])) + .pipe(util2.cleanNodeModule('account-provider-azure', ['node_modules/date-utils/doc/**', 'node_modules/adal_node/node_modules/**'], undefined)) + .pipe(util2.cleanNodeModule('typescript', ['**/**'], undefined)); // Original code commented out here // const localExtensionDependencies = () => gulp.src('extensions/node_modules/**', { base: '.' }); // const marketplaceExtensions = () => es.merge( diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 5262045a8f..25730a7bf3 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -370,6 +370,8 @@ export function packageExtensionsStream(optsIn?: IPackageExtensionsOptions): Nod const localExtensionDependencies = () => gulp.src(extensionDepsSrc, { base: '.', dot: true }) .pipe(filter(['**', '!**/package-lock.json'])) + .pipe(util2.cleanNodeModule('account-provider-azure', ['node_modules/date-utils/doc/**', 'node_modules/adal_node/node_modules/**'], undefined)) + .pipe(util2.cleanNodeModule('typescript', ['**/**'], undefined)); // Original code commented out here // const localExtensionDependencies = () => gulp.src('extensions/node_modules/**', { base: '.' }); diff --git a/build/lib/util.js b/build/lib/util.js index 175b6934b2..40563ca8e5 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -8,6 +8,7 @@ const es = require("event-stream"); const debounce = require("debounce"); const _filter = require("gulp-filter"); const rename = require("gulp-rename"); +const _ = require("underscore"); const path = require("path"); const fs = require("fs"); const _rimraf = require("rimraf"); @@ -99,18 +100,22 @@ function skipDirectories() { }); } exports.skipDirectories = skipDirectories; -function cleanNodeModules(rulePath) { - const rules = fs.readFileSync(rulePath, 'utf8') - .split(/\r?\n/g) - .map(line => line.trim()) - .filter(line => line && !/^#/.test(line)); - const excludes = rules.filter(line => !/^!/.test(line)).map(line => `!**/node_modules/${line}`); - const includes = rules.filter(line => /^!/.test(line)).map(line => `**/node_modules/${line.substr(1)}`); +function cleanNodeModule(name, excludes, includes) { + const toGlob = (path) => '**/node_modules/' + name + (path ? '/' + path : ''); + const negate = (str) => '!' + str; + const allFilter = _filter(toGlob('**'), { restore: true }); + const globs = [toGlob('**')].concat(excludes.map(_.compose(negate, toGlob))); const input = es.through(); - const output = es.merge(input.pipe(_filter(['**', ...excludes])), input.pipe(_filter(includes))); + const nodeModuleInput = input.pipe(allFilter); + let output = nodeModuleInput.pipe(_filter(globs)); + if (includes) { + const includeGlobs = includes.map(toGlob); + output = es.merge(output, nodeModuleInput.pipe(_filter(includeGlobs))); + } + output = output.pipe(allFilter.restore); return es.duplex(input, output); } -exports.cleanNodeModules = cleanNodeModules; +exports.cleanNodeModule = cleanNodeModule; function loadSourcemaps() { const input = es.through(); const output = input diff --git a/build/lib/util.ts b/build/lib/util.ts index 594086a5c8..95c8d996ef 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -132,21 +132,23 @@ export function skipDirectories(): NodeJS.ReadWriteStream { }); } -export function cleanNodeModules(rulePath: string): NodeJS.ReadWriteStream { - const rules = fs.readFileSync(rulePath, 'utf8') - .split(/\r?\n/g) - .map(line => line.trim()) - .filter(line => line && !/^#/.test(line)); +export function cleanNodeModule(name: string, excludes: string[], includes?: string[]): NodeJS.ReadWriteStream { + const toGlob = (path: string) => '**/node_modules/' + name + (path ? '/' + path : ''); + const negate = (str: string) => '!' + str; - const excludes = rules.filter(line => !/^!/.test(line)).map(line => `!**/node_modules/${line}`); - const includes = rules.filter(line => /^!/.test(line)).map(line => `**/node_modules/${line.substr(1)}`); + const allFilter = _filter(toGlob('**'), { restore: true }); + const globs = [toGlob('**')].concat(excludes.map(_.compose(negate, toGlob) as (x: string) => string)); const input = es.through(); - const output = es.merge( - input.pipe(_filter(['**', ...excludes])), - input.pipe(_filter(includes)) - ); + const nodeModuleInput = input.pipe(allFilter); + let output: NodeJS.ReadWriteStream = nodeModuleInput.pipe(_filter(globs)); + if (includes) { + const includeGlobs = includes.map(toGlob); + output = es.merge(output, nodeModuleInput.pipe(_filter(includeGlobs))); + } + + output = output.pipe(allFilter.restore); return es.duplex(input, output); } diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index e8cd0730ce..6decfcc826 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -60,18 +60,6 @@ interface PreviewStyleLoadErrorMessage extends WebviewMessage { }; } -export class PreviewDocumentVersion { - public constructor( - public readonly resource: vscode.Uri, - public readonly version: number, - ) { } - - public equals(other: PreviewDocumentVersion): boolean { - return this.resource.fsPath === other.resource.fsPath - && this.version === other.version; - } -} - export class MarkdownPreview extends Disposable { public static viewType = 'markdown.preview'; @@ -83,7 +71,7 @@ export class MarkdownPreview extends Disposable { private throttleTimer: any; private line: number | undefined = undefined; private firstUpdate = true; - private currentVersion?: PreviewDocumentVersion; + private currentVersion?: { resource: vscode.Uri, version: number }; private forceUpdate = false; private isScrolling = false; private _disposed: boolean = false; @@ -401,8 +389,7 @@ export class MarkdownPreview extends Disposable { return; } - const pendingVersion = new PreviewDocumentVersion(resource, document.version); - if (!this.forceUpdate && this.currentVersion && this.currentVersion.equals(pendingVersion)) { + if (!this.forceUpdate && this.currentVersion && this.currentVersion.resource.fsPath === resource.fsPath && this.currentVersion.version === document.version) { if (this.line) { this.updateForView(resource, this.line); } @@ -410,14 +397,10 @@ export class MarkdownPreview extends Disposable { } this.forceUpdate = false; - this.currentVersion = pendingVersion; + this.currentVersion = { resource, version: document.version }; if (this._resource === resource) { const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state); - // Another call to `doUpdate` may have happened. - // Make sure we are still updating for the correct document - if (this.currentVersion && this.currentVersion.equals(pendingVersion)) { - this.setContent(content); - } + this.setContent(content); } } diff --git a/extensions/package.json b/extensions/package.json index da7f9f2b32..8d41ef689c 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.5.0-dev.20190517" + "typescript": "3.4.5" }, "scripts": { "postinstall": "node ./postinstall" } -} +} \ No newline at end of file diff --git a/extensions/powershell/syntaxes/powershell.tmLanguage.json b/extensions/powershell/syntaxes/powershell.tmLanguage.json index b997667c5a..801ff729b9 100644 --- a/extensions/powershell/syntaxes/powershell.tmLanguage.json +++ b/extensions/powershell/syntaxes/powershell.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/PowerShell/EditorSyntax/commit/44eac8702f3cbe55a4ec70c1fdb163d42b4162fc", + "version": "https://github.com/PowerShell/EditorSyntax/commit/12b7d7257eb493e45a9af0af9094ec0c2a996712", "name": "PowerShell", "scopeName": "source.powershell", "patterns": [ @@ -252,7 +252,7 @@ ] }, "attribute": { - "begin": "(\\[)\\s*\\b(?i)(cmdletbinding|alias|outputtype|parameter|validatenotnull|validatenotnullorempty|validatecount|validateset|allownull|allowemptycollection|allowemptystring|validatescript|validaterange|validatepattern|validatelength|supportswildcards)\\b", + "begin": "(\\[)\\s*\\b(?i)(cmdletbinding|alias|outputtype|parameter|validatenotnull|validatenotnullorempty|validatecount|validateset|allownull|allowemptycollection|allowemptystring|validatescript|validaterange|validatepattern|validatelength)\\b", "beginCaptures": { "1": { "name": "punctuation.section.bracket.begin.powershell" @@ -283,6 +283,33 @@ } }, "patterns": [ + { + "include": "#variable" + }, + { + "include": "#variableNoProperty" + }, + { + "include": "#hashtable" + }, + { + "include": "#scriptblock" + }, + { + "include": "#doubleQuotedStringEscapes" + }, + { + "include": "#doubleQuotedString" + }, + { + "include": "#type" + }, + { + "include": "#numericConstant" + }, + { + "include": "#doubleQuotedString" + }, { "include": "$self" }, @@ -296,6 +323,17 @@ "name": "keyword.operator.assignment.powershell" } } + }, + { + "begin": "(?{1,5})}", - "name": "constant.character.escape.powershell" - }, - { - "match": "`u(?:\\{[0-9a-fA-F]{,6}.)?", - "name": "invalid.character.escape.powershell" - } - ] - }, "function": { "begin": "^(?:\\s*+)(?i)(function|filter|configuration|workflow)\\s+(?:(global|local|script|private):)?((?:\\p{L}|\\d|_|-|\\.)+)", "beginCaptures": { @@ -622,9 +644,6 @@ }, { "captures": { - "0": { - "name": "support.variable.automatic.powershell" - }, "1": { "name": "keyword.other.variable.definition.powershell" }, @@ -636,7 +655,7 @@ } }, "comment": "Automatic variables are not constants, but they are read-only. In monokai (default) color schema support.variable doesn't have color, so we use constant.", - "match": "(\\$)((?:[$^?])|(?i:_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This)\\b)((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?" + "match": "(\\$)(?i:(\\$|\\^|\\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?\\b" }, { "captures": { @@ -814,7 +833,7 @@ } }, "comment": "Automatic variables are not constants, but they are read-only...", - "match": "(\\$)((?:[$^?])|(?i:_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This)\\b)" + "match": "(\\$)(?i:(\\$|\\^|\\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))\\b" }, { "captures": { @@ -846,7 +865,7 @@ "name": "entity.name.function.invocation.powershell" } }, - "match": "(?i:(\\$)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))" + "match": "(?i:(\\$|@)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))" }, { "captures": { @@ -962,6 +981,9 @@ { "include": "#variableNoProperty" }, + { + "include": "#variable" + }, { "include": "#doubleQuotedStringEscapes" }, diff --git a/extensions/powershell/test/colorize-results/test_ps1.json b/extensions/powershell/test/colorize-results/test_ps1.json index 184fe2ce3c..8c691ac46d 100644 --- a/extensions/powershell/test/colorize-results/test_ps1.json +++ b/extensions/powershell/test/colorize-results/test_ps1.json @@ -694,24 +694,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell keyword.other.variable.definition.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "keyword: #569CD6" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.variable.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.constant.automatic.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "default: #FFFFFF" } }, { @@ -1068,24 +1068,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "keyword: #569CD6" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "default: #FFFFFF" } }, { @@ -1266,24 +1266,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "keyword: #569CD6" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "default: #FFFFFF" } }, { @@ -1431,24 +1431,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "keyword: #569CD6" } }, { "c": "matches", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "default: #FFFFFF" } }, { @@ -1508,24 +1508,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell keyword.other.variable.definition.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "keyword: #569CD6" } }, { "c": "matches", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", "r": { - "dark_plus": "support.variable: #9CDCFE", - "light_plus": "support.variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.variable: #9CDCFE" + "dark_plus": null, + "light_plus": null, + "dark_vs": null, + "light_vs": null, + "hc_black": "default: #FFFFFF" } }, { diff --git a/extensions/vscode-colorize-tests/package.json b/extensions/vscode-colorize-tests/package.json index 517429bb6d..763513a590 100644 --- a/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -8,7 +8,8 @@ "vscode": "*" }, "scripts": { - "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json" + "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json", + "postinstall": "node ./node_modules/vscode/bin/install" }, "devDependencies": { "@types/node": "^10.12.21", diff --git a/extensions/vscode-colorize-tests/src/typings/ref.d.ts b/extensions/vscode-colorize-tests/src/typings/ref.d.ts index 3a5401b477..9139021748 100644 --- a/extensions/vscode-colorize-tests/src/typings/ref.d.ts +++ b/extensions/vscode-colorize-tests/src/typings/ref.d.ts @@ -4,4 +4,3 @@ *--------------------------------------------------------------------------------------------*/ /// -/// diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 38c68f6e8f..149346bbb9 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.5.0-dev.20190517: - version "3.5.0-dev.20190517" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.0-dev.20190517.tgz#5a85f1091cf33fde39b04f898c5730e30edd3e39" - integrity sha512-KoBHq6ytEApXKTDtmTu4Sp/tC5SPe4FpvwutLEANhwdMPblqZdh7APuH7I/ceMlgfHSa7B00JgF7NokUJQi0/g== +typescript@3.4.5: + version "3.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" + integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== diff --git a/package.json b/package.json index 01beebaff8..e2f0685f5d 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "tslint": "node node_modules/tslint/bin/tslint -c tslint-gci.json -p src/tsconfig.json", "strict-null-check": "tsc -p src/tsconfig.strictNullChecks.json", "strict-null-check-watch": "tsc -p src/tsconfig.strictNullChecks.json --watch", - "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization", - "web": "node scripts/code-web.js" + "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization" }, "dependencies": { "@angular/animations": "~4.1.3", @@ -76,7 +75,7 @@ "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.14.0-beta2", + "vscode-xterm": "3.13.0-beta3", "yauzl": "^2.9.1", "yazl": "^2.4.3", "zone.js": "^0.8.4" @@ -132,7 +131,6 @@ "gulp-uglify": "^3.0.0", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", - "http-server": "^0.11.1", "husky": "^0.13.1", "innosetup-compiler": "^5.5.60", "is": "^3.1.0", @@ -145,7 +143,6 @@ "mkdirp": "^0.5.0", "mocha": "^2.2.5", "mocha-junit-reporter": "^1.17.0", - "opn": "^5.4.0", "optimist": "0.3.5", "p-all": "^1.0.0", "pump": "^1.0.1", @@ -158,7 +155,7 @@ "source-map": "^0.4.4", "temp-write": "^3.4.0", "ts-loader": "^4.4.2", - "tslint": "^5.16.0", + "tslint": "^5.11.0", "tslint-microsoft-contrib": "^6.0.0", "typemoq": "^0.3.2", "typescript": "3.4.5", diff --git a/scripts/code-web.js b/scripts/code-web.js deleted file mode 100644 index c4f3699f2a..0000000000 --- a/scripts/code-web.js +++ /dev/null @@ -1,14 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const httpServer = require('http-server'); -const opn = require('opn'); - -const url = 'http://127.0.0.1:8080/out/vs/code/browser/workbench/workbench.html'; - -httpServer.createServer({ root: '.', cache: 5 }).listen(8080); -console.log(`Open ${url} in your browser`); - -opn(url); \ No newline at end of file diff --git a/src/buildfile.js b/src/buildfile.js index 09b62e7f38..507ef3f818 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -12,7 +12,7 @@ exports.base = [{ }]; exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.main']); -exports.workbenchWeb = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.web.main']); +exports.workbenchNodeless = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.nodeless.main']); exports.code = require('./vs/code/buildfile').collectModules(); diff --git a/src/sql/base/browser/ui/checkbox/media/checkbox.css b/src/sql/base/browser/ui/checkbox/media/checkbox.css index 5efbb133c5..5485dc8982 100644 --- a/src/sql/base/browser/ui/checkbox/media/checkbox.css +++ b/src/sql/base/browser/ui/checkbox/media/checkbox.css @@ -14,7 +14,7 @@ background: url('check.svg') center center no-repeat; } -.vs-dark .custom-checkbox.sql-checkbox.checked { +.vs-dark.monaco-shell .custom-checkbox.sql-checkbox.checked { background: url('check_inverse.svg') center center no-repeat; } diff --git a/src/sql/base/browser/ui/taskbar/actionbar.ts b/src/sql/base/browser/ui/taskbar/actionbar.ts index 0b48545e73..9d4bafc707 100644 --- a/src/sql/base/browser/ui/taskbar/actionbar.ts +++ b/src/sql/base/browser/ui/taskbar/actionbar.ts @@ -7,8 +7,8 @@ import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { - IActionBarOptions, ActionsOrientation, IActionViewItem, - IActionOptions, ActionViewItem, BaseActionViewItem + IActionBarOptions, ActionsOrientation, IActionItem, + IActionOptions, ActionItem, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import * as lifecycle from 'vs/base/common/lifecycle'; import * as DOM from 'vs/base/browser/dom'; @@ -31,7 +31,7 @@ export class ActionBar extends ActionRunner implements IActionRunner { private _context: any; // Items - private _items: IActionViewItem[]; + private _items: IActionItem[]; private _focusedItem?: number; private _focusTracker: DOM.IFocusTracker; @@ -214,14 +214,14 @@ export class ActionBar extends ActionRunner implements IActionRunner { actionItemElement.className = 'action-item'; actionItemElement.setAttribute('role', 'presentation'); - let item: IActionViewItem | undefined = undefined; + let item: IActionItem | undefined = undefined; - if (this._options.actionViewItemProvider) { - item = this._options.actionViewItemProvider(action); + if (this._options.actionItemProvider) { + item = this._options.actionItemProvider(action); } if (!item) { - item = new ActionViewItem(this.context, action, options); + item = new ActionItem(this.context, action, options); } item.actionRunner = this._actionRunner; @@ -248,7 +248,7 @@ export class ActionBar extends ActionRunner implements IActionRunner { public clear(): void { // Do not dispose action items if they were provided from outside - this._items = this._options.actionViewItemProvider ? [] : lifecycle.dispose(this._items); + this._items = this._options.actionItemProvider ? [] : lifecycle.dispose(this._items); DOM.clearNode(this._actionsList); } @@ -274,7 +274,7 @@ export class ActionBar extends ActionRunner implements IActionRunner { } let startIndex = this._focusedItem; - let item: IActionViewItem; + let item: IActionItem; do { this._focusedItem = (this._focusedItem + 1) % this._items.length; @@ -294,7 +294,7 @@ export class ActionBar extends ActionRunner implements IActionRunner { } let startIndex = this._focusedItem; - let item: IActionViewItem; + let item: IActionItem; do { this._focusedItem = this._focusedItem - 1; @@ -343,7 +343,7 @@ export class ActionBar extends ActionRunner implements IActionRunner { // trigger action let actionItem = this._items[this._focusedItem]; - if (actionItem instanceof BaseActionViewItem) { + if (actionItem instanceof BaseActionItem) { const context = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context; this.run(actionItem._action, context); } diff --git a/src/sql/base/browser/ui/taskbar/taskbar.ts b/src/sql/base/browser/ui/taskbar/taskbar.ts index f0eb15a150..9f6b8e9649 100644 --- a/src/sql/base/browser/ui/taskbar/taskbar.ts +++ b/src/sql/base/browser/ui/taskbar/taskbar.ts @@ -43,8 +43,8 @@ export class Taskbar { this.actionBar = new ActionBar(element, { orientation: options.orientation, ariaLabel: options.ariaLabel, - actionViewItemProvider: (action: Action) => { - return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined; + actionItemProvider: (action: Action) => { + return options.actionItemProvider ? options.actionItemProvider(action) : undefined; } }); } diff --git a/src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts b/src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts index 1436116401..957e9c655b 100644 --- a/src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts +++ b/src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts @@ -397,7 +397,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements let isUntitled: boolean = uri.scheme === Schemas.untitled; const fileInput = isUntitled ? this._untitledEditorService.createOrGet(uri, notebookModeId, options.initialContent) : - this._editorService.createInput({ resource: uri, mode: notebookModeId }); + this._editorService.createInput({ resource: uri, language: notebookModeId }); let input = this._instantiationService.createInstance(NotebookInput, path.basename(uri.fsPath), uri, fileInput); input.defaultKernel = options.defaultKernel; input.connectionProfile = new ConnectionProfile(this._capabilitiesService, options.connectionProfile); diff --git a/src/sql/workbench/browser/modal/media/modal.css b/src/sql/workbench/browser/modal/media/modal.css index 8a51a2d278..684e331f3b 100644 --- a/src/sql/workbench/browser/modal/media/modal.css +++ b/src/sql/workbench/browser/modal/media/modal.css @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.modal { +.monaco-shell .modal { background-color: rgba(204, 204, 204, 0.6); right: 0; left: 0; @@ -13,7 +13,7 @@ z-index: 500; } -.modal:not(.flyout-dialog) .modal-dialog { +.monaco-shell .modal:not(.flyout-dialog) .modal-dialog { margin: auto; width: 640px; height: 480px; @@ -32,7 +32,7 @@ height: 25px; } -.modal.flyout-dialog .modal-dialog { +.monaco-shell .modal.flyout-dialog .modal-dialog { margin: auto auto auto auto; height: 100%; width: 500px; @@ -40,13 +40,14 @@ position: absolute; overflow-y: hidden; } -.modal.flyout-dialog.wide .modal-dialog { + +.monaco-shell .modal.flyout-dialog.wide .modal-dialog { width: 1200px; max-width: 95%; min-width: 400px; } -.modal.flyout-dialog .modal-content { +.monaco-shell .modal.flyout-dialog .modal-content { height: 100%; font-size: 11px; display: flex; @@ -65,10 +66,10 @@ margin-right: 10px; } -.modal.flyout-dialog .modal-body, -.modal.flyout-dialog .angular-modal-body, +.monaco-shell .modal.flyout-dialog .modal-body, +.monaco-shell .modal.flyout-dialog .angular-modal-body, /* Style for body and footer in modal dialog. This should be applied to dialog created with angular component. */ -.modal.flyout-dialog .modal-body-and-footer { +.monaco-shell .modal.flyout-dialog .modal-body-and-footer { flex: 1 1; overflow: hidden; } @@ -104,11 +105,11 @@ padding-left: 4px; } -.vs-dark .modal.flyout-dialog .input { +.vs-dark.monaco-shell .modal.flyout-dialog .input { background-color: #3C3C3C; } -.vs-dark .modal.flyout-dialog input:disabled { +.vs-dark.monaco-shell .modal.flyout-dialog input:disabled { background-color: #E1E1E1; color: #3C3C3C; } diff --git a/src/sql/workbench/browser/parts/views/customView.ts b/src/sql/workbench/browser/parts/views/customView.ts index 4dc9c96dab..895d06be67 100644 --- a/src/sql/workbench/browser/parts/views/customView.ts +++ b/src/sql/workbench/browser/parts/views/customView.ts @@ -10,6 +10,7 @@ import { IAction, ActionRunner, Action } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { ContextAwareMenuItemActionItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ViewContainer, ITreeItemLabel } from 'vs/workbench/common/views'; import { FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet'; @@ -21,7 +22,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import * as DOM from 'vs/base/browser/dom'; import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree'; import { ResourceLabel } from 'vs/workbench/browser/labels'; -import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { URI } from 'vs/base/common/uri'; import { basename } from 'vs/base/common/path'; import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -45,7 +46,6 @@ import { ITreeItem, ITreeView } from 'sql/workbench/common/views'; import { IOEShimService } from 'sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { NodeContextKey } from 'sql/workbench/parts/dataExplorer/common/nodeContext'; -import { fillInActionBarActions, fillInContextMenuActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; class TitleMenus implements IDisposable { @@ -319,7 +319,7 @@ export class CustomTreeView extends Disposable implements ITreeView { } private createTree() { - const actionItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined; + const actionItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuItemActionItem, action) : undefined; const menus = this.instantiationService.createInstance(TreeMenus, this.id); const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.container, this.id); const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, menus, actionItemProvider); @@ -599,7 +599,7 @@ class TreeRenderer implements IRenderer { constructor( private treeViewId: string, private menus: TreeMenus, - private actionItemProvider: IActionViewItemProvider, + private actionItemProvider: IActionItemProvider, @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchThemeService private themeService: IWorkbenchThemeService, @IConfigurationService private configurationService: IConfigurationService, @@ -623,7 +623,7 @@ class TreeRenderer implements IRenderer { DOM.addClass(resourceLabel.element.element, 'custom-view-tree-node-item-resourceLabel'); const actionsContainer = DOM.append(resourceLabel.element.element, DOM.$('.actions')); const actionBar = new ActionBar(actionsContainer, { - actionViewItemProvider: this.actionItemProvider, + actionItemProvider: this.actionItemProvider, actionRunner: new MultipleSelectionActionRunner(() => tree.getSelection()) }); @@ -769,10 +769,10 @@ class TreeController extends WorkbenchTreeController { getActions: () => actions, - getActionViewItem: (action) => { + getActionItem: (action) => { const keybinding = this._keybindingService.lookupKeybinding(action.id); if (keybinding) { - return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel() }); + return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel() }); } return null; }, diff --git a/src/sql/workbench/common/customInputConverter.ts b/src/sql/workbench/common/customInputConverter.ts index 86fc0fdf0a..d489cfe6ad 100644 --- a/src/sql/workbench/common/customInputConverter.ts +++ b/src/sql/workbench/common/customInputConverter.ts @@ -181,7 +181,7 @@ function getNotebookFileExtensions(instantiationService: IInstantiationService): function hasNotebookFileMode(input: EditorInput): boolean { if (input instanceof UntitledEditorInput) { let untitledCast: UntitledEditorInput = input; - return (untitledCast && untitledCast.getMode() === notebookModeId); + return (untitledCast && untitledCast.getModeId() === notebookModeId); } return false; } @@ -200,7 +200,7 @@ function withService(instantiationService: IInstantiationServ function hasSqlFileMode(input: EditorInput): boolean { if (input instanceof UntitledEditorInput) { let untitledCast: UntitledEditorInput = input; - return untitledCast && (untitledCast.getMode() === undefined || untitledCast.getMode() === sqlModeId); + return untitledCast && (untitledCast.getModeId() === undefined || untitledCast.getModeId() === sqlModeId); } return false; diff --git a/src/sql/workbench/electron-browser/modelComponents/webview.component.ts b/src/sql/workbench/electron-browser/modelComponents/webview.component.ts index b9b26d186c..7b5331f789 100644 --- a/src/sql/workbench/electron-browser/modelComponents/webview.component.ts +++ b/src/sql/workbench/electron-browser/modelComponents/webview.component.ts @@ -94,7 +94,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen private setHtml(): void { if (this._webview && this.html) { this._renderedHtml = this.html; - this._webview.html = this._renderedHtml; + this._webview.contents = this._renderedHtml; this._webview.layout(); } } diff --git a/src/sql/workbench/parts/dashboard/contents/webviewContent.component.ts b/src/sql/workbench/parts/dashboard/contents/webviewContent.component.ts index d20d7511c4..58a912e853 100644 --- a/src/sql/workbench/parts/dashboard/contents/webviewContent.component.ts +++ b/src/sql/workbench/parts/dashboard/contents/webviewContent.component.ts @@ -80,7 +80,7 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo public setHtml(html: string): void { this._html = html; if (this._webview) { - this._webview.html = html; + this._webview.contents = html; this._webview.layout(); } } @@ -112,7 +112,7 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo this._onMessage.fire(e); }); if (this._html) { - this._webview.html = this._html; + this._webview.contents = this._html; } this._webview.layout(); } diff --git a/src/sql/workbench/parts/dashboard/widgets/webview/webviewWidget.component.ts b/src/sql/workbench/parts/dashboard/widgets/webview/webviewWidget.component.ts index 87f68bbb9a..375add445d 100644 --- a/src/sql/workbench/parts/dashboard/widgets/webview/webviewWidget.component.ts +++ b/src/sql/workbench/parts/dashboard/widgets/webview/webviewWidget.component.ts @@ -60,7 +60,7 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget, public setHtml(html: string): void { this._html = html; if (this._webview) { - this._webview.html = html; + this._webview.contents = html; this._webview.layout(); } } @@ -110,7 +110,7 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget, this._onMessage.fire(e); }); if (this._html) { - this._webview.html = this._html; + this._webview.contents = this._html; } this._webview.layout(); } diff --git a/src/sql/workbench/parts/editData/browser/editDataActions.ts b/src/sql/workbench/parts/editData/browser/editDataActions.ts index a4a4e324ff..fe8301b719 100644 --- a/src/sql/workbench/parts/editData/browser/editDataActions.ts +++ b/src/sql/workbench/parts/editData/browser/editDataActions.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Action, IActionViewItem, IActionRunner } from 'vs/base/common/actions'; +import { Action, IActionItem, IActionRunner } from 'vs/base/common/actions'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IQueryModelService } from 'sql/platform/query/common/queryModel'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox'; @@ -150,7 +150,7 @@ export class ChangeMaxRowsAction extends EditDataAction { * Action item that handles the dropdown (combobox) that lists the avaliable number of row selections * for an edit data session */ -export class ChangeMaxRowsActionItem implements IActionViewItem { +export class ChangeMaxRowsActionItem implements IActionItem { public actionRunner: IActionRunner; public defaultRowCount: number; diff --git a/src/sql/workbench/parts/editData/browser/editDataEditor.ts b/src/sql/workbench/parts/editData/browser/editDataEditor.ts index 59fd9ec2c8..7c2d706e84 100644 --- a/src/sql/workbench/parts/editData/browser/editDataEditor.ts +++ b/src/sql/workbench/parts/editData/browser/editDataEditor.ts @@ -19,7 +19,7 @@ import { EditDataInput } from 'sql/workbench/parts/editData/common/editDataInput import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import * as queryContext from 'sql/workbench/parts/query/common/queryContext'; import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { IQueryModelService } from 'sql/platform/query/common/queryModel'; import { IEditorDescriptorService } from 'sql/workbench/services/queryEditor/common/editorDescriptorService'; @@ -313,7 +313,7 @@ export class EditDataEditor extends BaseEditor { // Create QueryTaskbar this._taskbarContainer = DOM.append(parentElement, DOM.$('div')); this._taskbar = new Taskbar(this._taskbarContainer, { - actionViewItemProvider: (action: Action) => this._getChangeMaxRowsAction(action) + actionItemProvider: (action: Action) => this._getChangeMaxRowsAction(action) }); // Create Actions for the toolbar @@ -344,7 +344,7 @@ export class EditDataEditor extends BaseEditor { /** * Gets the IActionItem for the list of row number drop down */ - private _getChangeMaxRowsAction(action: Action): IActionViewItem { + private _getChangeMaxRowsAction(action: Action): IActionItem { let actionID = ChangeMaxRowsAction.ID; if (action.id === actionID) { if (!this._changeMaxRowsActionItem) { diff --git a/src/sql/workbench/parts/jobManagement/electron-browser/media/jobHistory.css b/src/sql/workbench/parts/jobManagement/electron-browser/media/jobHistory.css index f924199f0c..f5089814b3 100644 --- a/src/sql/workbench/parts/jobManagement/electron-browser/media/jobHistory.css +++ b/src/sql/workbench/parts/jobManagement/electron-browser/media/jobHistory.css @@ -119,8 +119,8 @@ input#accordion:checked ~ .accordion-content { padding-bottom: 10px; } -.vs-dark .all-jobs >.back-button-icon, -.hc-black .all-jobs >.back-button-icon { +.vs-dark.monaco-shell .all-jobs >.back-button-icon, +.hc-black.monaco-shell .all-jobs >.back-button-icon { content: url('back_inverse.svg'); } diff --git a/src/sql/workbench/parts/notebook/notebook.component.ts b/src/sql/workbench/parts/notebook/notebook.component.ts index 88673d05d2..cdd4aca499 100644 --- a/src/sql/workbench/parts/notebook/notebook.component.ts +++ b/src/sql/workbench/parts/notebook/notebook.component.ts @@ -14,9 +14,10 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions'; -import { IAction, Action, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, Action, IActionItem } from 'vs/base/common/actions'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { AngularDisposable } from 'sql/base/node/lifecycle'; @@ -47,7 +48,6 @@ import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { ILogService } from 'vs/platform/log/common/log'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { LabeledMenuItemActionItem, fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; export const NOTEBOOK_SELECTOR: string = 'notebook-component'; @@ -405,7 +405,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe this._trustedAction.enabled = false; let taskbar = this.toolbar.nativeElement; - this._actionBar = new Taskbar(taskbar, { actionViewItemProvider: action => this.actionItemProvider(action as Action) }); + this._actionBar = new Taskbar(taskbar, { actionItemProvider: action => this.actionItemProvider(action as Action) }); this._actionBar.context = this; this._actionBar.setContent([ { action: addCodeCellButton }, @@ -419,7 +419,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe } - private actionItemProvider(action: Action): IActionViewItem { + private actionItemProvider(action: Action): IActionItem { // Check extensions to create ActionItem; otherwise, return undefined // This is similar behavior that exists in MenuItemActionItem if (action instanceof MenuItemAction) { diff --git a/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts b/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts index c52d8e36f1..842b257dcf 100644 --- a/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts +++ b/src/sql/workbench/parts/objectExplorer/browser/serverTreeActionProvider.ts @@ -8,6 +8,7 @@ import { ContributableActionProvider } from 'vs/workbench/browser/actions'; import { IAction } from 'vs/base/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { DisconnectConnectionAction, AddServerAction, @@ -30,7 +31,6 @@ import { TreeNodeContextKey } from 'sql/workbench/parts/objectExplorer/common/tr import { IQueryManagementService } from 'sql/platform/query/common/queryManagement'; import { IScriptingService } from 'sql/platform/scripting/common/scriptingService'; import { ServerInfoContextKey } from 'sql/workbench/parts/connection/common/serverInfoContextKey'; -import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; /** * Provides actions for the server tree elements diff --git a/src/sql/workbench/parts/query/browser/queryActions.ts b/src/sql/workbench/parts/query/browser/queryActions.ts index 911efdef30..5267252710 100644 --- a/src/sql/workbench/parts/query/browser/queryActions.ts +++ b/src/sql/workbench/parts/query/browser/queryActions.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/queryActions'; import * as nls from 'vs/nls'; -import { Action, IActionViewItem, IActionRunner } from 'vs/base/common/actions'; +import { Action, IActionItem, IActionRunner } from 'vs/base/common/actions'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -427,7 +427,7 @@ export class ListDatabasesAction extends QueryTaskbarAction { * Action item that handles the dropdown (combobox) that lists the available databases. * Based off StartDebugActionItem. */ -export class ListDatabasesActionItem implements IActionViewItem { +export class ListDatabasesActionItem implements IActionItem { public static ID = 'listDatabaseQueryActionItem'; public actionRunner: IActionRunner; diff --git a/src/sql/workbench/parts/query/browser/queryEditor.ts b/src/sql/workbench/parts/query/browser/queryEditor.ts index 137fa5a382..75bb2836e2 100644 --- a/src/sql/workbench/parts/query/browser/queryEditor.ts +++ b/src/sql/workbench/parts/query/browser/queryEditor.ts @@ -23,7 +23,7 @@ import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResour import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { ISelectionData } from 'azdata'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -463,7 +463,7 @@ export class QueryEditor extends BaseEditor { // Create QueryTaskbar this._taskbarContainer = DOM.append(parentElement, DOM.$('div')); this._taskbar = new Taskbar(this._taskbarContainer, { - actionViewItemProvider: (action: Action) => this._getActionItemForAction(action), + actionItemProvider: (action: Action) => this._getActionItemForAction(action), }); // Create Actions for the toolbar @@ -513,7 +513,7 @@ export class QueryEditor extends BaseEditor { * Gets the IActionItem for the List Databases dropdown if provided the associated Action. * Otherwise returns null. */ - private _getActionItemForAction(action: Action): IActionViewItem { + private _getActionItemForAction(action: Action): IActionItem { if (action.id === ListDatabasesAction.ID) { return this.listDatabasesActionItem; } diff --git a/src/sql/workbench/parts/query/common/queryInput.ts b/src/sql/workbench/parts/query/common/queryInput.ts index 8cdf076ca8..a0e8b43a8a 100644 --- a/src/sql/workbench/parts/query/common/queryInput.ts +++ b/src/sql/workbench/parts/query/common/queryInput.ts @@ -146,11 +146,8 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec // Description is shown beside the tab name in the combobox of open editors public getDescription(): string { return this._description; } public supportsSplitEditor(): boolean { return false; } - public getMode(): string { return QueryInput.SCHEMA; } + public getModeId(): string { return QueryInput.SCHEMA; } public revert(): Promise { return this._sql.revert(); } - public setMode(mode: string) { - this._sql.setMode(mode); - } public matches(otherInput: any): boolean { if (otherInput instanceof QueryInput) { diff --git a/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts b/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts index f6e8a4c847..23b3be8950 100644 --- a/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts +++ b/src/sql/workbench/parts/webview/electron-browser/webViewDialog.ts @@ -121,7 +121,7 @@ export class WebViewDialog extends Modal { } private updateDialogBody(): void { - this._webview.html = this.html; + this._webview.contents = this.html; } /* espace key */ diff --git a/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts b/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts index bb9ed7af72..9f246c33ff 100644 --- a/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts +++ b/src/sql/workbench/services/queryEditor/browser/queryEditorService.ts @@ -303,7 +303,7 @@ export class QueryEditorService implements IQueryEditorService { newEditorInput = queryInput; } else { let uriCopy: URI = URI.from({ scheme: uri.scheme, authority: uri.authority, path: uri.path, query: uri.query, fragment: uri.fragment }); - newEditorInput = QueryEditorService.instantiationService.createInstance(FileEditorInput, uriCopy, undefined, undefined); + newEditorInput = QueryEditorService.instantiationService.createInstance(FileEditorInput, uriCopy, undefined); } return newEditorInput; diff --git a/src/typings/vscode-xterm.d.ts b/src/typings/vscode-xterm.d.ts index 0e5e59a9b5..e425a37c43 100644 --- a/src/typings/vscode-xterm.d.ts +++ b/src/typings/vscode-xterm.d.ts @@ -101,6 +101,17 @@ declare module 'vscode-xterm' { */ experimentalCharAtlas?: 'none' | 'static' | 'dynamic'; + /** + * (EXPERIMENTAL) Defines which implementation to use for buffer lines. + * + * - 'JsArray': The default/stable implementation. + * - 'TypedArray': The new experimental implementation based on TypedArrays that is expected to + * significantly boost performance and memory consumption. Use at your own risk. + * + * @deprecated This option will be removed in the future. + */ + experimentalBufferLineImpl?: 'JsArray' | 'TypedArray'; + /** * The font size used to render text. */ @@ -188,18 +199,6 @@ declare module 'vscode-xterm' { * The color theme of the terminal. */ theme?: ITheme; - - /** - * Whether "Windows mode" is enabled. Because Windows backends winpty and - * conpty operate by doing line wrapping on their side, xterm.js does not - * have access to wrapped lines. When Windows mode is enabled the following - * changes will be in effect: - * - * - Reflow is disabled. - * - Lines are assumed to be wrapped if the last character of the line is - * not whitespace. - */ - windowsMode?: boolean; } /** @@ -275,7 +274,7 @@ declare module 'vscode-xterm' { * A callback that fires when the mouse leaves a link. Note that this can * happen even when tooltipCallback hasn't fired for the link yet. */ - leaveCallback?: () => void; + leaveCallback?: (event: MouseEvent, uri: string) => boolean | void; /** * The priority of the link matcher, this defines the order in which the link @@ -307,14 +306,6 @@ declare module 'vscode-xterm' { dispose(): void; } - /** - * An event that can be listened to. - * @returns an `IDisposable` to stop listening. - */ - export interface IEvent { - (listener: (e: T) => any): IDisposable; - } - export interface IMarker extends IDisposable { readonly id: number; readonly isDisposed: boolean; @@ -334,39 +325,28 @@ declare module 'vscode-xterm' { /** * The element containing the terminal. */ - readonly element: HTMLElement; + element: HTMLElement; /** * The textarea that accepts input for the terminal. */ - readonly textarea: HTMLTextAreaElement; + textarea: HTMLTextAreaElement; /** - * The number of rows in the terminal's viewport. Use - * `ITerminalOptions.rows` to set this in the constructor and - * `Terminal.resize` for when the terminal exists. + * The number of rows in the terminal's viewport. */ - readonly rows: number; + rows: number; /** - * The number of columns in the terminal's viewport. Use - * `ITerminalOptions.cols` to set this in the constructor and - * `Terminal.resize` for when the terminal exists. + * The number of columns in the terminal's viewport. */ - readonly cols: number; - - /** - * (EXPERIMENTAL) The terminal's current buffer, this might be either the - * normal buffer or the alt buffer depending on what's running in the - * terminal. - */ - readonly buffer: IBuffer; + cols: number; /** * (EXPERIMENTAL) Get all markers registered against the buffer. If the alt * buffer is active this will always return []. */ - readonly markers: ReadonlyArray; + markers: IMarker[]; /** * Natural language strings that can be localized. @@ -380,70 +360,6 @@ declare module 'vscode-xterm' { */ constructor(options?: ITerminalOptions); - /** - * Adds an event listener for the cursor moves. - * @returns an `IDisposable` to stop listening. - */ - onCursorMove: IEvent; - - /** - * Adds an event listener for when a data event fires. This happens for - * example when the user types or pastes into the terminal. The event value - * is whatever `string` results, in a typical setup, this should be passed - * on to the backing pty. - * @returns an `IDisposable` to stop listening. - */ - onData: IEvent; - - /** - * Adds an event listener for a key is pressed. The event value contains the - * string that will be sent in the data event as well as the DOM event that - * triggered it. - * @returns an `IDisposable` to stop listening. - */ - onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; - - /** - * Adds an event listener for when a line feed is added. - * @returns an `IDisposable` to stop listening. - */ - onLineFeed: IEvent; - - /** - * Adds an event listener for when a scroll occurs. The event value is the - * new position of the viewport. - * @returns an `IDisposable` to stop listening. - */ - onScroll: IEvent; - - /** - * Adds an event listener for when a selection change occurs. - * @returns an `IDisposable` to stop listening. - */ - onSelectionChange: IEvent; - - /** - * Adds an event listener for when rows are rendered. The event value - * contains the start row and end rows of the rendered area (ranges from `0` - * to `Terminal.rows - 1`). - * @returns an `IDisposable` to stop listening. - */ - onRender: IEvent<{ start: number, end: number }>; - - /** - * Adds an event listener for when the terminal is resized. The event value - * contains the new size. - * @returns an `IDisposable` to stop listening. - */ - onResize: IEvent<{ cols: number, rows: number }>; - - /** - * Adds an event listener for when an OSC 0 or OSC 2 title change occurs. - * The event value is the new title. - * @returns an `IDisposable` to stop listening. - */ - onTitleChange: IEvent; - /** * Unfocus the terminal. */ @@ -458,63 +374,54 @@ declare module 'vscode-xterm' { * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'blur' | 'focus' | 'linefeed' | 'selection', listener: () => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'data', listener: (...args: any[]) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'key', listener: (key: string, event: KeyboardEvent) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'keypress' | 'keydown', listener: (event: KeyboardEvent) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'refresh', listener: (data: { start: number, end: number }) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'resize', listener: (data: { cols: number, rows: number }) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'scroll', listener: (ydisp: number) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: 'title', listener: (title: string) => void): void; /** * Registers an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener)` instead. */ on(type: string, listener: (...args: any[]) => void): void; @@ -522,7 +429,6 @@ declare module 'vscode-xterm' { * Deregisters an event listener. * @param type The type of the event. * @param listener The listener. - * @deprecated use `Terminal.onEvent(listener).dispose()` instead. */ off(type: 'blur' | 'focus' | 'linefeed' | 'selection' | 'data' | 'key' | 'keypress' | 'keydown' | 'refresh' | 'resize' | 'scroll' | 'title' | string, listener: (...args: any[]) => void): void; @@ -540,19 +446,22 @@ declare module 'vscode-xterm' { * be used to conveniently remove the event listener. * @param type The type of event. * @param handler The event handler. - * @deprecated use `Terminal.onEvent(listener)` instead. */ addDisposableListener(type: string, handler: (...args: any[]) => void): IDisposable; /** - * Resizes the terminal. It's best practice to debounce calls to resize, - * this will help ensure that the pty can respond to the resize event - * before another one occurs. + * Resizes the terminal. * @param x The number of columns to resize to. * @param y The number of rows to resize to. */ resize(columns: number, rows: number): void; + /** + * Writes text to the terminal, followed by a break line character (\n). + * @param data The text to write to the terminal. + */ + writeln(data: string): void; + /** * Opens the terminal within an element. * @param parent The element to create the terminal within. This element @@ -567,35 +476,11 @@ declare module 'vscode-xterm' { * should be processed by the terminal and what keys should not. * @param customKeyEventHandler The custom KeyboardEvent handler to attach. * This is a function that takes a KeyboardEvent, allowing consumers to stop - * propagation and/or prevent the default action. The function returns + * propogation and/or prevent the default action. The function returns * whether the event should be processed by xterm.js. */ attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; - /** - * (EXPERIMENTAL) Adds a handler for CSI escape sequences. - * @param flag The flag should be one-character string, which specifies the - * final character (e.g "m" for SGR) of the CSI sequence. - * @param callback The function to handle the escape sequence. The callback - * is called with the numerical params, as well as the special characters - * (e.g. "$" for DECSCPP). Return true if the sequence was handled; false if - * we should try a previous handler (set by addCsiHandler or setCsiHandler). - * The most recently-added handler is tried first. - * @return An IDisposable you can call to remove this handler. - */ - addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable; - - /** - * (EXPERIMENTAL) Adds a handler for OSC escape sequences. - * @param ident The number (first parameter) of the sequence. - * @param callback The function to handle the escape sequence. The callback - * is called with OSC data string. Return true if the sequence was handled; - * false if we should try a previous handler (set by addOscHandler or - * setOscHandler). The most recently-added handler is tried first. - * @return An IDisposable you can call to remove this handler. - */ - addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; - /** * (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to * be matched and handled. @@ -670,24 +555,11 @@ declare module 'vscode-xterm' { */ getSelection(): string; - /** - * Gets the selection position or undefined if there is no selection. - */ - getSelectionPosition(): ISelectionPosition | undefined; - /** * Clears the current terminal selection. */ clearSelection(): void; - /** - * Selects text within the terminal. - * @param column The column the selection starts at.. - * @param row The row the selection starts at. - * @param length The length of the selection. - */ - select(column: number, row: number, length: number): void; - /** * Selects all text within the terminal. */ @@ -752,20 +624,6 @@ declare module 'vscode-xterm' { */ write(data: string): void; - /** - * Writes text to the terminal, followed by a break line character (\n). - * @param data The text to write to the terminal. - */ - writeln(data: string): void; - - /** - * Writes UTF8 data to the terminal. - * This has a slight performance advantage over the string based write method - * due to lesser data conversions needed on the way from the pty to xterm.js. - * @param data The data to write to the terminal. - */ - writeUtf8(data: Uint8Array): void; - /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -775,7 +633,7 @@ declare module 'vscode-xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; + getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -826,7 +684,7 @@ declare module 'vscode-xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; + setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. @@ -881,134 +739,8 @@ declare module 'vscode-xterm' { * Applies an addon to the Terminal prototype, making it available to all * newly created Terminals. * @param addon The addon to apply. - * @deprecated Use the new loadAddon API/addon format. */ static applyAddon(addon: any): void; - - /** - * (EXPERIMENTAL) Loads an addon into this instance of xterm.js. - * @param addon The addon to load. - */ - loadAddon(addon: ITerminalAddon): void; - } - - /** - * An addon that can provide additional functionality to the terminal. - */ - export interface ITerminalAddon extends IDisposable { - /** - * (EXPERIMENTAL) This is called when the addon is activated within xterm.js. - */ - activate(terminal: Terminal): void; - } - - /** - * An object representing a selecrtion within the terminal. - */ - interface ISelectionPosition { - /** - * The start column of the selection. - */ - startColumn: number; - - /** - * The start row of the selection. - */ - startRow: number; - - /** - * The end column of the selection. - */ - endColumn: number; - - /** - * The end row of the selection. - */ - endRow: number; - } - - interface IBuffer { - /** - * The y position of the cursor. This ranges between `0` (when the - * cursor is at baseY) and `Terminal.rows - 1` (when the cursor is on the - * last row). - */ - readonly cursorY: number; - - /** - * The x position of the cursor. This ranges between `0` (left side) and - * `Terminal.cols - 1` (right side). - */ - readonly cursorX: number; - - /** - * The line within the buffer where the top of the viewport is. - */ - readonly viewportY: number; - - /** - * The line within the buffer where the top of the bottom page is (when - * fully scrolled down); - */ - readonly baseY: number; - - /** - * The amount of lines in the buffer. - */ - readonly length: number; - - /** - * Gets a line from the buffer, or undefined if the line index does not exist. - * - * Note that the result of this function should be used immediately after calling as when the - * terminal updates it could lead to unexpected behavior. - * - * @param y The line index to get. - */ - getLine(y: number): IBufferLine | undefined; - } - - interface IBufferLine { - /** - * Whether the line is wrapped from the previous line. - */ - readonly isWrapped: boolean; - - /** - * Gets a cell from the line, or undefined if the line index does not exist. - * - * Note that the result of this function should be used immediately after calling as when the - * terminal updates it could lead to unexpected behavior. - * - * @param x The character index to get. - */ - getCell(x: number): IBufferCell; - - /** - * Gets the line as a string. Note that this is gets only the string for the line, not taking - * isWrapped into account. - * - * @param trimRight Whether to trim any whitespace at the right of the line. - * @param startColumn The column to start from (inclusive). - * @param endColumn The column to end at (exclusive). - */ - translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string; - } - - interface IBufferCell { - /** - * The character within the cell. - */ - readonly char: string; - - /** - * The width of the character. Some examples: - * - * - This is `1` for most cells. - * - This is `2` for wide character like CJK glyphs. - * - This is `0` for cells immediately following cells with a width of `2`. - */ - readonly width: number; } } @@ -1018,10 +750,22 @@ declare module 'vscode-xterm' { interface TerminalCore { debug: boolean; + buffer: { + y: number; + ybase: number; + ydisp: number; + x: number; + lines: any[]; + + translateBufferLineToString(lineIndex: number, trimRight: boolean): string; + }; + handler(text: string): void; - _onScroll: IEventEmitter2; - _onKey: IEventEmitter2<{ key: string }>; + /** + * Emit an event on the terminal. + */ + emit(type: string, data: any): void; charMeasure?: { height: number, width: number }; @@ -1031,10 +775,6 @@ declare module 'vscode-xterm' { }; } - interface IEventEmitter2 { - fire(e: T): void; - } - interface ISearchOptions { /** * Whether the find should be done as a regex. @@ -1054,6 +794,7 @@ declare module 'vscode-xterm' { _core: TerminalCore; webLinksInit(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void; + winptyCompatInit(): void; /** * Find the next instance of the term, then scroll to and select it. If it diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index b388c4ead7..0f99d839e8 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -45,13 +45,13 @@ class WindowManager { // --- Pixel Ratio public getPixelRatio(): number { - let ctx: any = document.createElement('canvas').getContext('2d'); + let ctx = document.createElement('canvas').getContext('2d'); let dpr = window.devicePixelRatio || 1; - let bsr = ctx.webkitBackingStorePixelRatio || - ctx.mozBackingStorePixelRatio || - ctx.msBackingStorePixelRatio || - ctx.oBackingStorePixelRatio || - ctx.backingStorePixelRatio || 1; + let bsr = (ctx).webkitBackingStorePixelRatio || + (ctx).mozBackingStorePixelRatio || + (ctx).msBackingStorePixelRatio || + (ctx).oBackingStorePixelRatio || + (ctx).backingStorePixelRatio || 1; return dpr / bsr; } diff --git a/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts index a4434d722a..557f16c86a 100644 --- a/src/vs/base/browser/contextmenu.ts +++ b/src/vs/base/browser/contextmenu.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { SubmenuAction } from 'vs/base/browser/ui/menu/menu'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; @@ -25,7 +25,7 @@ export class ContextSubMenu extends SubmenuAction { export interface IContextMenuDelegate { getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; }; getActions(): Array; - getActionViewItem?(action: IAction): IActionViewItem | undefined; + getActionItem?(action: IAction): IActionItem | undefined; getActionsContext?(event?: IContextMenuEvent): any; getKeyBinding?(action: IAction): ResolvedKeybinding | undefined; getMenuClassName?(): string; diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index d400bbadf3..b2908db913 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -329,7 +329,7 @@ function parseFormattedText(content: string): IFormatParseTree { children: [] }; - let actionViewItemIndex = 0; + let actionItemIndex = 0; let current = root; const stack: IFormatParseTree[] = []; const stream = new StringStream(content); @@ -359,8 +359,8 @@ function parseFormattedText(content: string): IFormatParseTree { }; if (type === FormatType.Action) { - newCurrent.index = actionViewItemIndex; - actionViewItemIndex++; + newCurrent.index = actionItemIndex; + actionItemIndex++; } current.children!.push(newCurrent); diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index ea3d32745f..ca685b7bc8 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -18,7 +18,7 @@ import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview import { Event, Emitter } from 'vs/base/common/event'; import { asArray } from 'vs/base/common/arrays'; -export interface IActionViewItem { +export interface IActionItem { actionRunner: IActionRunner; setActionContext(context: any): void; render(element: HTMLElement): void; @@ -28,12 +28,12 @@ export interface IActionViewItem { dispose(): void; } -export interface IBaseActionViewItemOptions { +export interface IBaseActionItemOptions { draggable?: boolean; isMenu?: boolean; } -export class BaseActionViewItem extends Disposable implements IActionViewItem { +export class BaseActionItem extends Disposable implements IActionItem { element?: HTMLElement; _context: any; @@ -41,7 +41,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { private _actionRunner: IActionRunner; - constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) { + constructor(context: any, action: IAction, protected options?: IBaseActionItemOptions) { super(); this._context = context || this; @@ -226,20 +226,20 @@ export class Separator extends Action { } } -export interface IActionViewItemOptions extends IBaseActionViewItemOptions { +export interface IActionItemOptions extends IBaseActionItemOptions { icon?: boolean; label?: boolean; keybinding?: string | null; } -export class ActionViewItem extends BaseActionViewItem { +export class ActionItem extends BaseActionItem { protected label: HTMLElement; - protected options: IActionViewItemOptions; + protected options: IActionItemOptions; private cssClass?: string; - constructor(context: any, action: IAction, options: IActionViewItemOptions = {}) { + constructor(context: any, action: IAction, options: IActionItemOptions = {}) { super(context, action, options); this.options = options; @@ -363,14 +363,14 @@ export interface ActionTrigger { keyDown: boolean; } -export interface IActionViewItemProvider { - (action: IAction): IActionViewItem | undefined; +export interface IActionItemProvider { + (action: IAction): IActionItem | undefined; } export interface IActionBarOptions { orientation?: ActionsOrientation; context?: any; - actionViewItemProvider?: IActionViewItemProvider; + actionItemProvider?: IActionItemProvider; actionRunner?: IActionRunner; ariaLabel?: string; animated?: boolean; @@ -386,7 +386,7 @@ const defaultOptions: IActionBarOptions = { } }; -export interface IActionOptions extends IActionViewItemOptions { +export interface IActionOptions extends IActionItemOptions { index?: number; } @@ -397,8 +397,8 @@ export class ActionBar extends Disposable implements IActionRunner { private _actionRunner: IActionRunner; private _context: any; - // View Items - viewItems: IActionViewItem[]; + // Items + items: IActionItem[]; protected focusedItem?: number; private focusTracker: DOM.IFocusTracker; @@ -438,7 +438,7 @@ export class ActionBar extends Disposable implements IActionRunner { this._register(this._actionRunner.onDidRun(e => this._onDidRun.fire(e))); this._register(this._actionRunner.onDidBeforeRun(e => this._onDidBeforeRun.fire(e))); - this.viewItems = []; + this.items = []; this.focusedItem = undefined; this.domNode = document.createElement('div'); @@ -575,7 +575,7 @@ export class ActionBar extends Disposable implements IActionRunner { set context(context: any) { this._context = context; - this.viewItems.forEach(i => i.setActionContext(context)); + this.items.forEach(i => i.setActionContext(context)); } get actionRunner(): IActionRunner { @@ -585,7 +585,7 @@ export class ActionBar extends Disposable implements IActionRunner { set actionRunner(actionRunner: IActionRunner) { if (actionRunner) { this._actionRunner = actionRunner; - this.viewItems.forEach(item => item.actionRunner = actionRunner); + this.items.forEach(item => item.actionRunner = actionRunner); } } @@ -599,36 +599,36 @@ export class ActionBar extends Disposable implements IActionRunner { let index = types.isNumber(options.index) ? options.index : null; actions.forEach((action: IAction) => { - const actionViewItemElement = document.createElement('li'); - actionViewItemElement.className = 'action-item'; - actionViewItemElement.setAttribute('role', 'presentation'); + const actionItemElement = document.createElement('li'); + actionItemElement.className = 'action-item'; + actionItemElement.setAttribute('role', 'presentation'); // Prevent native context menu on actions - this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => { + this._register(DOM.addDisposableListener(actionItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => { e.preventDefault(); e.stopPropagation(); })); - let item: IActionViewItem | undefined; + let item: IActionItem | undefined; - if (this.options.actionViewItemProvider) { - item = this.options.actionViewItemProvider(action); + if (this.options.actionItemProvider) { + item = this.options.actionItemProvider(action); } if (!item) { - item = new ActionViewItem(this.context, action, options); + item = new ActionItem(this.context, action, options); } item.actionRunner = this._actionRunner; item.setActionContext(this.context); - item.render(actionViewItemElement); + item.render(actionItemElement); if (index === null || index < 0 || index >= this.actionsList.children.length) { - this.actionsList.appendChild(actionViewItemElement); - this.viewItems.push(item); + this.actionsList.appendChild(actionItemElement); + this.items.push(item); } else { - this.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]); - this.viewItems.splice(index, 0, item); + this.actionsList.insertBefore(actionItemElement, this.actionsList.children[index]); + this.items.splice(index, 0, item); index++; } }); @@ -657,23 +657,23 @@ export class ActionBar extends Disposable implements IActionRunner { } pull(index: number): void { - if (index >= 0 && index < this.viewItems.length) { + if (index >= 0 && index < this.items.length) { this.actionsList.removeChild(this.actionsList.childNodes[index]); - dispose(this.viewItems.splice(index, 1)); + dispose(this.items.splice(index, 1)); } } clear(): void { - this.viewItems = dispose(this.viewItems); + this.items = dispose(this.items); DOM.clearNode(this.actionsList); } length(): number { - return this.viewItems.length; + return this.items.length; } isEmpty(): boolean { - return this.viewItems.length === 0; + return this.items.length === 0; } focus(index?: number): void; @@ -691,7 +691,7 @@ export class ActionBar extends Disposable implements IActionRunner { if (selectFirst && typeof this.focusedItem === 'undefined') { // Focus the first enabled item - this.focusedItem = this.viewItems.length - 1; + this.focusedItem = this.items.length - 1; this.focusNext(); } else { if (index !== undefined) { @@ -704,15 +704,15 @@ export class ActionBar extends Disposable implements IActionRunner { protected focusNext(): void { if (typeof this.focusedItem === 'undefined') { - this.focusedItem = this.viewItems.length - 1; + this.focusedItem = this.items.length - 1; } const startIndex = this.focusedItem; - let item: IActionViewItem; + let item: IActionItem; do { - this.focusedItem = (this.focusedItem + 1) % this.viewItems.length; - item = this.viewItems[this.focusedItem]; + this.focusedItem = (this.focusedItem + 1) % this.items.length; + item = this.items[this.focusedItem]; } while (this.focusedItem !== startIndex && !item.isEnabled()); if (this.focusedItem === startIndex && !item.isEnabled()) { @@ -728,16 +728,16 @@ export class ActionBar extends Disposable implements IActionRunner { } const startIndex = this.focusedItem; - let item: IActionViewItem; + let item: IActionItem; do { this.focusedItem = this.focusedItem - 1; if (this.focusedItem < 0) { - this.focusedItem = this.viewItems.length - 1; + this.focusedItem = this.items.length - 1; } - item = this.viewItems[this.focusedItem]; + item = this.items[this.focusedItem]; } while (this.focusedItem !== startIndex && !item.isEnabled()); if (this.focusedItem === startIndex && !item.isEnabled()) { @@ -752,21 +752,21 @@ export class ActionBar extends Disposable implements IActionRunner { this.actionsList.focus(); } - for (let i = 0; i < this.viewItems.length; i++) { - const item = this.viewItems[i]; - const actionViewItem = item; + for (let i = 0; i < this.items.length; i++) { + const item = this.items[i]; + const actionItem = item; if (i === this.focusedItem) { - if (types.isFunction(actionViewItem.isEnabled)) { - if (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) { - actionViewItem.focus(fromRight); + if (types.isFunction(actionItem.isEnabled)) { + if (actionItem.isEnabled() && types.isFunction(actionItem.focus)) { + actionItem.focus(fromRight); } else { this.actionsList.focus(); } } } else { - if (types.isFunction(actionViewItem.blur)) { - actionViewItem.blur(); + if (types.isFunction(actionItem.blur)) { + actionItem.blur(); } } } @@ -778,16 +778,16 @@ export class ActionBar extends Disposable implements IActionRunner { } // trigger action - const actionViewItem = this.viewItems[this.focusedItem]; - if (actionViewItem instanceof BaseActionViewItem) { - const context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context; - this.run(actionViewItem._action, context); + const actionItem = this.items[this.focusedItem]; + if (actionItem instanceof BaseActionItem) { + const context = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context; + this.run(actionItem._action, context); } } private cancel(): void { if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); // remove focus from focused action + (document.activeElement).blur(); // remove focus from focused action } this._onDidCancel.fire(); @@ -798,8 +798,8 @@ export class ActionBar extends Disposable implements IActionRunner { } dispose(): void { - dispose(this.viewItems); - this.viewItems = []; + dispose(this.items); + this.items = []; DOM.removeNode(this.getContainer()); @@ -807,7 +807,7 @@ export class ActionBar extends Disposable implements IActionRunner { } } -export class SelectActionViewItem extends BaseActionViewItem { +export class SelectActionItem extends BaseActionItem { protected selectBox: SelectBox; constructor(ctx: any, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) { diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 47adfc1499..9a2f02ddb0 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -11,7 +11,7 @@ import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as objects from 'vs/base/common/objects'; -import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; export interface ICheckboxOpts extends ICheckboxStyles { @@ -28,7 +28,7 @@ const defaultOpts = { inputActiveOptionBorder: Color.fromHex('#007ACC') }; -export class CheckboxActionViewItem extends BaseActionViewItem { +export class CheckboxActionItem extends BaseActionItem { private checkbox: Checkbox; private disposables: IDisposable[] = []; diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 5729f405c2..655f74850a 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -132,13 +132,13 @@ export class ContextView extends Disposable { ContextView.BUBBLE_UP_EVENTS.forEach(event => { toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { - this.onDOMEvent(e, false); + this.onDOMEvent(e, document.activeElement, false); })); }); ContextView.BUBBLE_DOWN_EVENTS.forEach(event => { toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { - this.onDOMEvent(e, true); + this.onDOMEvent(e, document.activeElement, true); }, true)); }); @@ -213,11 +213,13 @@ export class ContextView extends Disposable { height: elementPosition.height }; } else { + let realAnchor = anchor; + around = { - top: anchor.y, - left: anchor.x, - width: anchor.width || 1, - height: anchor.height || 2 + top: realAnchor.y, + left: realAnchor.x, + width: realAnchor.width || 1, + height: realAnchor.height || 2 }; } @@ -276,7 +278,7 @@ export class ContextView extends Disposable { return !!this.delegate; } - private onDOMEvent(e: Event, onCapture: boolean): void { + private onDOMEvent(e: Event, element: HTMLElement, onCapture: boolean): void { if (this.delegate) { if (this.delegate.onDOMEvent) { this.delegate.onDOMEvent(e, document.activeElement); diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index a3bd38835b..68cbae533b 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -6,7 +6,7 @@ import 'vs/css!./dropdown'; import { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch'; import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions'; -import { BaseActionViewItem, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextViewProvider, IAnchor, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IMenuOptions } from 'vs/base/browser/ui/menu/menu'; @@ -247,7 +247,7 @@ export class DropdownMenu extends BaseDropdown { getAnchor: () => this.element, getActions: () => this.actions, getActionsContext: () => this.menuOptions ? this.menuOptions.context : null, - getActionViewItem: action => this.menuOptions && this.menuOptions.actionViewItemProvider ? this.menuOptions.actionViewItemProvider(action) : undefined, + getActionItem: action => this.menuOptions && this.menuOptions.actionItemProvider ? this.menuOptions.actionItemProvider(action) : undefined, getKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined, getMenuClassName: () => this.menuClassName, onHide: () => this.onHide(), @@ -266,23 +266,23 @@ export class DropdownMenu extends BaseDropdown { } } -export class DropdownMenuActionViewItem extends BaseActionViewItem { +export class DropdownMenuActionItem extends BaseActionItem { private menuActionsOrProvider: any; private dropdownMenu: DropdownMenu; private contextMenuProvider: IContextMenuProvider; - private actionViewItemProvider?: IActionViewItemProvider; + private actionItemProvider?: IActionItemProvider; private keybindings?: (action: IAction) => ResolvedKeybinding | undefined; private clazz: string | undefined; private anchorAlignmentProvider: (() => AnchorAlignment) | undefined; - constructor(action: IAction, menuActions: IAction[], contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); - constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); - constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) { + constructor(action: IAction, menuActions: IAction[], contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); + constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); + constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) { super(null, action); this.menuActionsOrProvider = menuActionsOrProvider; this.contextMenuProvider = contextMenuProvider; - this.actionViewItemProvider = actionViewItemProvider; + this.actionItemProvider = actionItemProvider; this.actionRunner = actionRunner; this.keybindings = keybindings; this.clazz = clazz; @@ -319,7 +319,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { this.dropdownMenu = this._register(new DropdownMenu(container, options)); this.dropdownMenu.menuOptions = { - actionViewItemProvider: this.actionViewItemProvider, + actionItemProvider: this.actionItemProvider, actionRunner: this.actionRunner, getKeyBinding: this.keybindings, context: this._context diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 1d72186b6b..2222629934 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -161,7 +161,7 @@ export class InputBox extends Widget { let tagName = this.options.flexibleHeight ? 'textarea' : 'input'; let wrapper = dom.append(this.element, $('.wrapper')); - this.input = dom.append(wrapper, $(tagName + '.input')); + this.input = dom.append(wrapper, $(tagName + '.input')); this.input.setAttribute('autocorrect', 'off'); this.input.setAttribute('autocapitalize', 'off'); this.input.setAttribute('spellcheck', 'false'); diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index c61060cafa..6dff868dff 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -7,7 +7,7 @@ import 'vs/css!./menu'; import * as nls from 'vs/nls'; import * as strings from 'vs/base/common/strings'; import { IActionRunner, IAction, Action } from 'vs/base/common/actions'; -import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, ActionsOrientation, Separator, ActionItem, IActionItemOptions, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -39,7 +39,7 @@ export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = createMenuEscapedMnemonicRegE export interface IMenuOptions { context?: any; - actionViewItemProvider?: IActionViewItemProvider; + actionItemProvider?: IActionItemProvider; actionRunner?: IActionRunner; getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined; ariaLabel?: string; @@ -70,7 +70,7 @@ interface ISubMenuData { } export class Menu extends ActionBar { - private mnemonics: Map>; + private mnemonics: Map>; private menuDisposables: IDisposable[]; private scrollableElement: DomScrollableElement; private menuElement: HTMLElement; @@ -88,7 +88,7 @@ export class Menu extends ActionBar { super(menuElement, { orientation: ActionsOrientation.VERTICAL, - actionViewItemProvider: action => this.doGetActionViewItem(action, options, parentData), + actionItemProvider: action => this.doGetActionItem(action, options, parentData), context: options.context, actionRunner: options.actionRunner, ariaLabel: options.ariaLabel, @@ -113,7 +113,7 @@ export class Menu extends ActionBar { const actions = this.mnemonics.get(key)!; if (actions.length === 1) { - if (actions[0] instanceof SubmenuMenuActionViewItem) { + if (actions[0] instanceof SubmenuActionItem) { this.focusItemByElement(actions[0].container); } @@ -138,7 +138,7 @@ export class Menu extends ActionBar { const event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.Home) || event.equals(KeyCode.PageUp)) { - this.focusedItem = this.viewItems.length - 1; + this.focusedItem = this.items.length - 1; this.focusNext(); EventHelper.stop(e, true); } else if (event.equals(KeyCode.End) || event.equals(KeyCode.PageDown)) { @@ -189,7 +189,7 @@ export class Menu extends ActionBar { parent: this }; - this.mnemonics = new Map>(); + this.mnemonics = new Map>(); this.push(actions, { icon: true, label: true, isMenu: true }); @@ -223,7 +223,7 @@ export class Menu extends ActionBar { container.appendChild(this.scrollableElement.getDomNode()); this.scrollableElement.scanDomNode(); - this.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item: BaseMenuActionViewItem, index: number, array: any[]) => { + this.items.filter(item => !(item instanceof MenuSeparatorActionItem)).forEach((item: MenuActionItem, index: number, array: any[]) => { item.updatePositionInSet(index + 1, array.length); }); } @@ -241,9 +241,9 @@ export class Menu extends ActionBar { this.domNode.style.backgroundColor = bgColor; container.style.boxShadow = shadow; - if (this.viewItems) { - this.viewItems.forEach(item => { - if (item instanceof BaseMenuActionViewItem || item instanceof MenuSeparatorActionViewItem) { + if (this.items) { + this.items.forEach(item => { + if (item instanceof MenuActionItem || item instanceof MenuSeparatorActionItem) { item.style(style); } }); @@ -263,12 +263,12 @@ export class Menu extends ActionBar { } trigger(index: number): void { - if (index <= this.viewItems.length && index >= 0) { - const item = this.viewItems[index]; - if (item instanceof SubmenuMenuActionViewItem) { + if (index <= this.items.length && index >= 0) { + const item = this.items[index]; + if (item instanceof SubmenuActionItem) { super.focus(index); item.open(true); - } else if (item instanceof BaseMenuActionViewItem) { + } else if (item instanceof MenuActionItem) { super.run(item._action, item._context); } else { return; @@ -295,27 +295,27 @@ export class Menu extends ActionBar { } } - private doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem { + private doGetActionItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionItem { if (action instanceof Separator) { - return new MenuSeparatorActionViewItem(options.context, action, { icon: true }); + return new MenuSeparatorActionItem(options.context, action, { icon: true }); } else if (action instanceof SubmenuAction) { - const menuActionViewItem = new SubmenuMenuActionViewItem(action, action.entries, parentData, options); + const menuActionItem = new SubmenuActionItem(action, action.entries, parentData, options); if (options.enableMnemonics) { - const mnemonic = menuActionViewItem.getMnemonic(); - if (mnemonic && menuActionViewItem.isEnabled()) { - let actionViewItems: BaseMenuActionViewItem[] = []; + const mnemonic = menuActionItem.getMnemonic(); + if (mnemonic && menuActionItem.isEnabled()) { + let actionItems: MenuActionItem[] = []; if (this.mnemonics.has(mnemonic)) { - actionViewItems = this.mnemonics.get(mnemonic)!; + actionItems = this.mnemonics.get(mnemonic)!; } - actionViewItems.push(menuActionViewItem); + actionItems.push(menuActionItem); - this.mnemonics.set(mnemonic, actionViewItems); + this.mnemonics.set(mnemonic, actionItems); } } - return menuActionViewItem; + return menuActionItem; } else { const menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics }; if (options.getKeyBinding) { @@ -329,32 +329,32 @@ export class Menu extends ActionBar { } } - const menuActionViewItem = new BaseMenuActionViewItem(options.context, action, menuItemOptions); + const menuActionItem = new MenuActionItem(options.context, action, menuItemOptions); if (options.enableMnemonics) { - const mnemonic = menuActionViewItem.getMnemonic(); - if (mnemonic && menuActionViewItem.isEnabled()) { - let actionViewItems: BaseMenuActionViewItem[] = []; + const mnemonic = menuActionItem.getMnemonic(); + if (mnemonic && menuActionItem.isEnabled()) { + let actionItems: MenuActionItem[] = []; if (this.mnemonics.has(mnemonic)) { - actionViewItems = this.mnemonics.get(mnemonic)!; + actionItems = this.mnemonics.get(mnemonic)!; } - actionViewItems.push(menuActionViewItem); + actionItems.push(menuActionItem); - this.mnemonics.set(mnemonic, actionViewItems); + this.mnemonics.set(mnemonic, actionItems); } } - return menuActionViewItem; + return menuActionItem; } } } -interface IMenuItemOptions extends IActionViewItemOptions { +interface IMenuItemOptions extends IActionItemOptions { enableMnemonics?: boolean; } -class BaseMenuActionViewItem extends BaseActionViewItem { +class MenuActionItem extends BaseActionItem { public container: HTMLElement; @@ -562,7 +562,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { } } -class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { +class SubmenuActionItem extends MenuActionItem { private mysubmenu: Menu | null; private submenuContainer: HTMLElement | undefined; private submenuIndicator: HTMLElement; @@ -778,7 +778,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { } } -class MenuSeparatorActionViewItem extends ActionViewItem { +class MenuSeparatorActionItem extends ActionItem { style(style: IMenuStyles): void { this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : null; } diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index ed5149a0cd..f586e880dc 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -41,8 +41,8 @@ class SelectListRenderer implements IListRendererObject.create(null); data.disposables = []; data.root = container; data.text = dom.append(container, $('.option-text')); @@ -54,10 +54,10 @@ class SelectListRenderer implements IListRenderertemplateData; + const text = (element).text; + const decoratorRight = (element).decoratorRight; + const isDisabled = (element).isDisabled; data.text.textContent = text; data.decoratorRight.innerText = (!!decoratorRight ? decoratorRight : ''); @@ -73,10 +73,10 @@ class SelectListRenderer implements IListRendererdata.root), 'option-disabled'); } else { // Make sure we do class removal from prior template rendering - dom.removeClass(data.root, 'option-disabled'); + dom.removeClass((data.root), 'option-disabled'); } } @@ -836,9 +836,9 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate { for (let i = 0; i < element.childNodes.length; i++) { - const child = element.childNodes.item(i); + const child = element.childNodes.item(i); - const tagName = child.tagName && child.tagName.toLowerCase(); + const tagName = (child).tagName && (child).tagName.toLowerCase(); if (tagName === 'img') { element.removeChild(child); } else { diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 2f33b06bdd..d3891181af 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -234,8 +234,8 @@ export class SplitView extends Disposable { }); const sashEventMapper = this.orientation === Orientation.VERTICAL - ? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey }) - : (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey }); + ? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey } as ISashEvent) + : (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey } as ISashEvent); const onStart = Event.map(sash.onDidStart, sashEventMapper); const onStartDisposable = onStart(this.onSashStart, this); diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 7d08f03117..698a220b97 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -6,8 +6,8 @@ import 'vs/css!./toolbar'; import * as nls from 'vs/nls'; import { Action, IActionRunner, IAction } from 'vs/base/common/actions'; -import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IContextMenuProvider, DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown'; +import { ActionBar, ActionsOrientation, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IContextMenuProvider, DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; @@ -17,7 +17,7 @@ export const CONTEXT = 'context.toolbar'; export interface IToolBarOptions { orientation?: ActionsOrientation; - actionViewItemProvider?: IActionViewItemProvider; + actionItemProvider?: IActionItemProvider; ariaLabel?: string; getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined; actionRunner?: IActionRunner; @@ -32,7 +32,7 @@ export class ToolBar extends Disposable { private options: IToolBarOptions; private actionBar: ActionBar; private toggleMenuAction: ToggleMenuAction; - private toggleMenuActionViewItem?: DropdownMenuActionViewItem; + private toggleMenuActionItem?: DropdownMenuActionItem; private hasSecondaryActions: boolean; private lookupKeybindings: boolean; @@ -42,7 +42,7 @@ export class ToolBar extends Disposable { this.options = options; this.lookupKeybindings = typeof this.options.getKeyBinding === 'function'; - this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionViewItem && this.toggleMenuActionViewItem.show(), options.toggleMenuTitle)); + this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionItem && this.toggleMenuActionItem.show(), options.toggleMenuTitle)); let element = document.createElement('div'); element.className = 'monaco-toolbar'; @@ -52,33 +52,33 @@ export class ToolBar extends Disposable { orientation: options.orientation, ariaLabel: options.ariaLabel, actionRunner: options.actionRunner, - actionViewItemProvider: (action: Action) => { + actionItemProvider: (action: Action) => { // Return special action item for the toggle menu action if (action.id === ToggleMenuAction.ID) { // Dispose old - if (this.toggleMenuActionViewItem) { - this.toggleMenuActionViewItem.dispose(); + if (this.toggleMenuActionItem) { + this.toggleMenuActionItem.dispose(); } // Create new - this.toggleMenuActionViewItem = new DropdownMenuActionViewItem( + this.toggleMenuActionItem = new DropdownMenuActionItem( action, (action).menuActions, contextMenuProvider, - this.options.actionViewItemProvider, + this.options.actionItemProvider, this.actionRunner, this.options.getKeyBinding, 'toolbar-toggle-more', this.options.anchorAlignmentProvider ); - this.toggleMenuActionViewItem!.setActionContext(this.actionBar.context); + this.toggleMenuActionItem!.setActionContext(this.actionBar.context); - return this.toggleMenuActionViewItem; + return this.toggleMenuActionItem; } - return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined; + return options.actionItemProvider ? options.actionItemProvider(action) : undefined; } })); } @@ -93,8 +93,8 @@ export class ToolBar extends Disposable { set context(context: any) { this.actionBar.context = context; - if (this.toggleMenuActionViewItem) { - this.toggleMenuActionViewItem.setActionContext(context); + if (this.toggleMenuActionItem) { + this.toggleMenuActionItem.setActionContext(context); } } @@ -156,9 +156,9 @@ export class ToolBar extends Disposable { } dispose(): void { - if (this.toggleMenuActionViewItem) { - this.toggleMenuActionViewItem.dispose(); - this.toggleMenuActionViewItem = undefined; + if (this.toggleMenuActionItem) { + this.toggleMenuActionItem.dispose(); + this.toggleMenuActionItem = undefined; } super.dispose(); diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index dca4a79f2c..93f55a6409 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -29,7 +29,7 @@ export interface IActionRunner extends IDisposable { onDidBeforeRun: Event; } -export interface IActionViewItem { +export interface IActionItem { actionRunner: IActionRunner; setActionContext(context: any): void; render(element: any /* HTMLElement */): void; diff --git a/src/vs/base/common/console.ts b/src/vs/base/common/console.ts index 5ea6aefe13..70232b47d2 100644 --- a/src/vs/base/common/console.ts +++ b/src/vs/base/common/console.ts @@ -79,7 +79,7 @@ export function getFirstFrame(arg0: IRemoteConsoleLog | string | undefined): ISt uri: URI.file(matches[1]), line: Number(matches[2]), column: Number(matches[3]) - }; + } as IStackFrame; } } diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index 7483613ee8..80736ee8a2 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -139,22 +139,19 @@ export function isUNC(path: string): boolean { } // Reference: https://en.wikipedia.org/wiki/Filename -const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g; -const UNIX_INVALID_FILE_CHARS = /[\\/]/g; +const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g; const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; -export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean { - const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS; - +export function isValidBasename(name: string | null | undefined): boolean { if (!name || name.length === 0 || /^\s+$/.test(name)) { return false; // require a name that is not just whitespace } - invalidFileChars.lastIndex = 0; // the holy grail of software development - if (invalidFileChars.test(name)) { + INVALID_FILE_CHARS.lastIndex = 0; // the holy grail of software development + if (INVALID_FILE_CHARS.test(name)) { return false; // check for certain invalid file characters } - if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { + if (isWindows && WINDOWS_FORBIDDEN_NAMES.test(name)) { return false; // check for certain invalid file names } @@ -162,16 +159,16 @@ export function isValidBasename(name: string | null | undefined, isWindowsOS: bo return false; // check for reserved values } - if (isWindowsOS && name[name.length - 1] === '.') { + if (isWindows && name[name.length - 1] === '.') { return false; // Windows: file cannot end with a "." } - if (isWindowsOS && name.length !== name.trim().length) { + if (isWindows && name.length !== name.trim().length) { return false; // Windows: file cannot end with a whitespace } if (name.length > 255) { - return false; // most file systems do not allow files > 255 length + return false; // most file systems do not allow files > 255 lenth } return true; diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index af16456a13..fa281cf1ef 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -197,11 +197,7 @@ function guessMimeTypeByFirstline(firstLine: string): string | null { } if (firstLine.length > 0) { - - // We want to prioritize associations based on the order they are registered so that the last registered - // association wins over all other. This is for https://github.com/Microsoft/vscode/issues/20074 - for (let i = registeredAssociations.length - 1; i >= 0; i--) { - const association = registeredAssociations[i]; + for (const association of registeredAssociations) { if (!association.firstline) { continue; } @@ -234,11 +230,10 @@ export function isUnspecific(mime: string[] | string): boolean { * 2. Otherwise, if there are other extensions, suggest the first one. * 3. Otherwise, suggest the prefix. */ -export function suggestFilename(mode: string | undefined, prefix: string): string { +export function suggestFilename(langId: string | null, prefix: string): string { const extensions = registeredAssociations - .filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === mode) + .filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === langId) .map(assoc => assoc.extension); - const extensionsWithDotFirst = coalesce(extensions) .filter(assoc => startsWith(assoc, '.')); diff --git a/src/vs/base/common/objects.ts b/src/vs/base/common/objects.ts index 1b734d0364..c8c1586c73 100644 --- a/src/vs/base/common/objects.ts +++ b/src/vs/base/common/objects.ts @@ -14,7 +14,7 @@ export function deepClone(obj: T): T { return obj as any; } const result: any = Array.isArray(obj) ? [] : {}; - Object.keys(obj as any).forEach((key: string) => { + Object.keys(obj).forEach((key: string) => { if (obj[key] && typeof obj[key] === 'object') { result[key] = deepClone(obj[key]); } else { diff --git a/src/vs/base/common/parsers.ts b/src/vs/base/common/parsers.ts index 35489f1881..3694cef195 100644 --- a/src/vs/base/common/parsers.ts +++ b/src/vs/base/common/parsers.ts @@ -79,7 +79,7 @@ export abstract class Parser { this._problemReporter.fatal(message); } - protected static merge(destination: T, source: T, overwrite: boolean): void { + protected static merge(destination: T, source: T, overwrite: boolean): void { Object.keys(source).forEach((key: string) => { const destValue = destination[key]; const sourceValue = source[key]; diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index b1fa46c8e3..d4888386ec 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -176,46 +176,28 @@ export function isAbsolutePath(resource: URI): boolean { /** * Returns true if the URI path has a trailing path separator */ -export function hasTrailingPathSeparator(resource: URI, sep: string = paths.sep): boolean { +export function hasTrailingPathSeparator(resource: URI): boolean { if (resource.scheme === Schemas.file) { const fsp = originalFSPath(resource); - return fsp.length > extpath.getRoot(fsp).length && fsp[fsp.length - 1] === sep; + return fsp.length > extpath.getRoot(fsp).length && fsp[fsp.length - 1] === paths.sep; } else { const p = resource.path; return p.length > 1 && p.charCodeAt(p.length - 1) === CharCode.Slash; // ignore the slash at offset 0 } } + /** - * Removes a trailing path separator, if there's one. + * Removes a trailing path seperator, if theres one. * Important: Doesn't remove the first slash, it would make the URI invalid */ -export function removeTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI { - if (hasTrailingPathSeparator(resource, sep)) { +export function removeTrailingPathSeparator(resource: URI): URI { + if (hasTrailingPathSeparator(resource)) { return resource.with({ path: resource.path.substr(0, resource.path.length - 1) }); } return resource; } -/** - * Adds a trailing path separator to the URI if there isn't one already. - * For example, c:\ would be unchanged, but c:\users would become c:\users\ - */ -export function addTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI { - let isRootSep: boolean = false; - if (resource.scheme === Schemas.file) { - const fsp = originalFSPath(resource); - isRootSep = ((fsp !== undefined) && (fsp.length === extpath.getRoot(fsp).length) && (fsp[fsp.length - 1] === sep)); - } else { - sep = '/'; - const p = resource.path; - isRootSep = p.length === 1 && p.charCodeAt(p.length - 1) === CharCode.Slash; - } - if (!isRootSep && !hasTrailingPathSeparator(resource, sep)) { - return resource.with({ path: resource.path + '/' }); - } - return resource; -} /** * Returns a relative path between two URIs. If the URIs don't have the same schema or authority, `undefined` is returned. diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 058a2f59ee..658ec817a9 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -233,7 +233,7 @@ export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean { // We check against an empty string. If the regular expression doesn't advance // (e.g. ends in an endless loop) it will match an empty string. const match = regexp.exec(''); - return !!(match && regexp.lastIndex === 0); + return !!(match && regexp.lastIndex === 0); } export function regExpContainsBackreference(regexpValue: string): boolean { diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index bf908f49a0..40d63048d1 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -670,15 +670,4 @@ export async function mkdirp(path: string, mode?: number, token?: CancellationTo // Any other error return Promise.reject(error); } -} - -// See https://github.com/Microsoft/vscode/issues/30180 -const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB -const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB - -// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149 -const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB -const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB - -export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE; -export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE; \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts index 5b4d173cb8..e160fcd467 100644 --- a/src/vs/base/node/request.ts +++ b/src/vs/base/node/request.ts @@ -159,7 +159,7 @@ export function asText(context: IRequestContext): Promise { }); } -export function asJson(context: IRequestContext): Promise { +export function asJson(context: IRequestContext): Promise { return new Promise((c, e) => { if (!isSuccess(context)) { return e('Server returned ' + context.res.statusCode); diff --git a/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts index 4148a623b4..f3edba5460 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -218,7 +218,7 @@ class ProtocolReader extends Disposable { // save new state => next time will read the body this._state.readHead = false; this._state.readLen = buff.readUInt32BE(9); - this._state.messageType = buff.readUInt8(0); + this._state.messageType = buff.readUInt8(0); this._state.id = buff.readUInt32BE(1); this._state.ack = buff.readUInt32BE(5); } else { diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 03b2da2c2e..75e7c50847 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -36,11 +36,11 @@ let IDS = 0; export class QuickOpenItemAccessorClass implements IItemAccessor { getItemLabel(entry: QuickOpenEntry): string | null { - return types.withUndefinedAsNull(entry.getLabel()); + return entry.getLabel(); } getItemDescription(entry: QuickOpenEntry): string | null { - return types.withUndefinedAsNull(entry.getDescription()); + return entry.getDescription(); } getItemPath(entry: QuickOpenEntry): string | undefined { @@ -75,15 +75,15 @@ export class QuickOpenEntry { /** * The label of the entry to identify it from others in the list */ - getLabel(): string | undefined { - return undefined; + getLabel(): string | null { + return null; } /** * The options for the label to use for this entry */ - getLabelOptions(): IIconLabelValueOptions | undefined { - return undefined; + getLabelOptions(): IIconLabelValueOptions | null { + return null; } /** @@ -97,51 +97,51 @@ export class QuickOpenEntry { /** * Detail information about the entry that is optional and can be shown below the label */ - getDetail(): string | undefined { - return undefined; + getDetail(): string | null { + return null; } /** * The icon of the entry to identify it from others in the list */ - getIcon(): string | undefined { - return undefined; + getIcon(): string | null { + return null; } /** * A secondary description that is optional and can be shown right to the label */ - getDescription(): string | undefined { - return undefined; + getDescription(): string | null { + return null; } /** * A tooltip to show when hovering over the entry. */ - getTooltip(): string | undefined { - return undefined; + getTooltip(): string | null { + return null; } /** * A tooltip to show when hovering over the description portion of the entry. */ - getDescriptionTooltip(): string | undefined { - return undefined; + getDescriptionTooltip(): string | null { + return null; } /** * An optional keybinding to show for an entry. */ - getKeybinding(): ResolvedKeybinding | undefined { - return undefined; + getKeybinding(): ResolvedKeybinding | null { + return null; } /** * A resource for this entry. Resource URIs can be used to compare different kinds of entries and group * them together. */ - getResource(): URI | undefined { - return undefined; + getResource(): URI | null { + return null; } /** @@ -229,11 +229,11 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { this.withBorder = showBorder; } - getLabel(): string | undefined { + getLabel(): string | null { return this.entry ? this.entry.getLabel() : super.getLabel(); } - getLabelOptions(): IIconLabelValueOptions | undefined { + getLabelOptions(): IIconLabelValueOptions | null { return this.entry ? this.entry.getLabelOptions() : super.getLabelOptions(); } @@ -241,19 +241,19 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry ? this.entry.getAriaLabel() : super.getAriaLabel(); } - getDetail(): string | undefined { + getDetail(): string | null { return this.entry ? this.entry.getDetail() : super.getDetail(); } - getResource(): URI | undefined { + getResource(): URI | null { return this.entry ? this.entry.getResource() : super.getResource(); } - getIcon(): string | undefined { + getIcon(): string | null { return this.entry ? this.entry.getIcon() : super.getIcon(); } - getDescription(): string | undefined { + getDescription(): string | null { return this.entry ? this.entry.getDescription() : super.getDescription(); } @@ -459,13 +459,13 @@ class Renderer implements IRenderer { // Label const options: IIconLabelValueOptions = entry.getLabelOptions() || Object.create(null); options.matches = labelHighlights || []; - options.title = entry.getTooltip(); - options.descriptionTitle = entry.getDescriptionTooltip() || entry.getDescription(); // tooltip over description because it could overflow + options.title = types.withNullAsUndefined(entry.getTooltip()); + options.descriptionTitle = entry.getDescriptionTooltip() || types.withNullAsUndefined(entry.getDescription()); // tooltip over description because it could overflow options.descriptionMatches = descriptionHighlights || []; - data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), entry.getDescription(), options); + data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), types.withNullAsUndefined(entry.getDescription()), options); // Meta - data.detail.set(entry.getDetail(), detailHighlights); + data.detail.set(types.withNullAsUndefined(entry.getDetail()), detailHighlights); // Keybinding data.keybinding.set(entry.getKeybinding()!); @@ -556,7 +556,7 @@ export class QuickOpenModel implements } getLabel(entry: QuickOpenEntry): string | null { - return types.withUndefinedAsNull(entry.getLabel()); + return entry.getLabel(); } getAriaLabel(entry: QuickOpenEntry): string { diff --git a/src/vs/base/test/common/mime.test.ts b/src/vs/base/test/common/mime.test.ts index dc41e96bb1..0cc9bfce43 100644 --- a/src/vs/base/test/common/mime.test.ts +++ b/src/vs/base/test/common/mime.test.ts @@ -6,7 +6,6 @@ import * as assert from 'assert'; import { guessMimeTypes, registerTextMime, suggestFilename } from 'vs/base/common/mime'; suite('Mime', () => { - test('Dynamically Register Text Mime', () => { let guess = guessMimeTypes('foo.monaco'); assert.deepEqual(guess, ['application/unknown']); @@ -57,11 +56,6 @@ suite('Mime', () => { registerTextMime({ id: 'docker', filepattern: 'dockerfile*', mime: 'text/looser' }); guess = guessMimeTypes('dockerfile'); assert.deepEqual(guess, ['text/winner', 'text/plain']); - - registerTextMime({ id: 'azure-looser', mime: 'text/azure-looser', firstline: /azure/ }); - registerTextMime({ id: 'azure-winner', mime: 'text/azure-winner', firstline: /azure/ }); - guess = guessMimeTypes('azure', 'azure'); - assert.deepEqual(guess, ['text/azure-winner', 'text/plain']); }); test('Specificity priority 1', () => { diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts index 8a4150feed..863b125f7b 100644 --- a/src/vs/base/test/common/resources.test.ts +++ b/src/vs/base/test/common/resources.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator } from 'vs/base/common/resources'; +import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { toSlashes } from 'vs/base/common/extpath'; @@ -178,9 +178,6 @@ suite('Resources', () => { assertEqualURI(removeTrailingPathSeparator(u1), expected, u1.toString()); } - function assertAddTrailingSeparator(u1: URI, expected: URI) { - assertEqualURI(addTrailingPathSeparator(u1), expected, u1.toString()); - } test('trailingPathSeparator', () => { assertTrailingSeparator(URI.parse('foo://a/foo'), false); @@ -193,11 +190,6 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/')); assertRemoveTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a')); - assertAddTrailingSeparator(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/')); - assertAddTrailingSeparator(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo/')); - assertAddTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/')); - assertAddTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a/')); - if (isWindows) { assertTrailingSeparator(URI.file('c:\\a\\foo'), false); assertTrailingSeparator(URI.file('c:\\a\\foo\\'), true); @@ -210,12 +202,6 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.file('c:\\'), URI.file('c:\\')); assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some')); assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\'), URI.file('\\\\server\\share\\')); - - assertAddTrailingSeparator(URI.file('c:\\a\\foo'), URI.file('c:\\a\\foo\\')); - assertAddTrailingSeparator(URI.file('c:\\a\\foo\\'), URI.file('c:\\a\\foo\\')); - assertAddTrailingSeparator(URI.file('c:\\'), URI.file('c:\\')); - assertAddTrailingSeparator(URI.file('\\\\server\\share\\some'), URI.file('\\\\server\\share\\some\\')); - assertAddTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some\\')); } else { assertTrailingSeparator(URI.file('/foo/bar'), false); assertTrailingSeparator(URI.file('/foo/bar/'), true); @@ -224,16 +210,12 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar')); assertRemoveTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar')); assertRemoveTrailingSeparator(URI.file('/'), URI.file('/')); - - assertAddTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar/')); - assertAddTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar/')); - assertAddTrailingSeparator(URI.file('/'), URI.file('/')); } }); function assertEqualURI(actual: URI, expected: URI, message?: string) { if (!isEqual(expected, actual)) { - assert.equal(actual.toString(), expected.toString(), message); + assert.equal(expected.toString(), actual.toString(), message); } } diff --git a/src/vs/base/test/node/config.test.ts b/src/vs/base/test/node/config.test.ts index 98743764b3..eafcfb3fe1 100644 --- a/src/vs/base/test/node/config.test.ts +++ b/src/vs/base/test/node/config.test.ts @@ -20,7 +20,7 @@ suite('Config', () => { const newDir = path.join(parentDir, 'config', id); const testFile = path.join(newDir, 'config.json'); - let watcher = new ConfigWatcher<{}>(testFile); + let watcher = new ConfigWatcher(testFile); let config = watcher.getConfig(); assert.ok(config); diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html deleted file mode 100644 index 832b6033bf..0000000000 --- a/src/vs/code/browser/workbench/workbench.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js deleted file mode 100644 index dbaf27c590..0000000000 --- a/src/vs/code/browser/workbench/workbench.js +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - function loadScript(path, callback) { - let script = document.createElement('script'); - script.onload = callback; - script.async = true; - script.type = 'text/javascript'; - script.src = path; - document.head.appendChild(script); - } - - loadScript('../../../../../out/vs/loader.js', function () { - - // @ts-ignore - require.config({ - baseUrl: `${window.location.origin}/out` - }); - - // @ts-ignore - require([ - 'vs/workbench/workbench.web.main', - 'vs/nls!vs/workbench/workbench.web.main', - 'vs/css!vs/workbench/workbench.web.main' - ], - // @ts-ignore - function () { - - // @ts-ignore - require('vs/workbench/browser/web.main').main().then(undefined, console.error); - }); - }); -})(); \ No newline at end of file diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 90ab9dd0a1..8e06bc1362 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -106,8 +106,8 @@ function showPartsSplash(configuration) { const style = document.createElement('style'); style.className = 'initialShellColors'; document.head.appendChild(style); - document.body.className = baseTheme; - style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; }`; + document.body.className = `monaco-shell ${baseTheme}`; + style.innerHTML = `.monaco-shell { background-color: ${shellBackground}; color: ${shellForeground}; }`; if (data && data.layoutInfo) { // restore parts if possible (we might not always store layout info) diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.html b/src/vs/code/electron-browser/workbench/workbench.nodeless.html new file mode 100644 index 0000000000..e37abfdf5a --- /dev/null +++ b/src/vs/code/electron-browser/workbench/workbench.nodeless.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.js b/src/vs/code/electron-browser/workbench/workbench.nodeless.js new file mode 100644 index 0000000000..fefcbc7a74 --- /dev/null +++ b/src/vs/code/electron-browser/workbench/workbench.nodeless.js @@ -0,0 +1,67 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check +'use strict'; + +(function () { + + function uriFromPath(_path) { + let pathName = _path.replace(/\\/g, '/'); + if (pathName.length > 0 && pathName.charAt(0) !== '/') { + pathName = '/' + pathName; + } + + let uri; + if (navigator.userAgent.indexOf('Windows') >= 0 && pathName.startsWith('//')) { // specially handle Windows UNC paths + uri = encodeURI('file:' + pathName); + } else { + uri = encodeURI('file://' + pathName); + } + + return uri.replace(/#/g, '%23'); + } + + function parseURLQueryArgs() { + const search = window.location.search || ''; + + return search.split(/[?&]/) + .filter(function (param) { return !!param; }) + .map(function (param) { return param.split('='); }) + .filter(function (param) { return param.length === 2; }) + .reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {}); + } + + function loadScript(path, callback) { + let script = document.createElement('script'); + script.onload = callback; + script.async = true; + script.type = 'text/javascript'; + script.src = path; + document.head.appendChild(script); + } + + loadScript('../../../../../out/vs/loader.js', function () { + + const args = parseURLQueryArgs(); + const configuration = JSON.parse(args['config'] || '{}') || {}; + + // @ts-ignore + require.config({ + baseUrl: uriFromPath(configuration.appRoot) + '/out', + }); + + // @ts-ignore + require([ + 'vs/workbench/workbench.nodeless.main', + 'vs/nls!vs/workbench/workbench.nodeless.main', + 'vs/css!vs/workbench/workbench.nodeless.main' + ], function () { + + // @ts-ignore + require('vs/workbench/browser/nodeless.main').main().then(undefined, console.error); + }); + }); +})(); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index eae9dc72f3..2073b305eb 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -234,7 +234,7 @@ export class CodeApplication extends Disposable { ipc.on('vscode:fetchShellEnv', (event: Event) => { const webContents = event.sender; - getShellEnvironment(this.logService).then(shellEnv => { + getShellEnvironment().then(shellEnv => { if (!webContents.isDestroyed()) { webContents.send('vscode:acceptShellEnv', shellEnv); } @@ -678,7 +678,7 @@ export class CodeApplication extends Disposable { historyMainService.onRecentlyOpenedChange(() => historyMainService.updateWindowsJumpList()); // Start shared process after a while - const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment(this.logService).then(userEnv => this.sharedProcess.spawn(userEnv)), 3000)); + const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment().then(userEnv => this.sharedProcess.spawn(userEnv)), 3000)); sharedProcessSpawn.schedule(); } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 25e058b554..b4d897b858 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -55,7 +55,7 @@ function setupIPC(accessor: ServicesAccessor): Promise { logService.trace('Sending some foreground love to the running instance:', processId); try { - const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); + const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); allowSetForegroundWindow(processId); } catch (e) { // noop diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index bf981ce16a..7c682fe74e 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -8,7 +8,7 @@ import * as objects from 'vs/base/common/objects'; import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { IStateService } from 'vs/platform/state/common/state'; -import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display } from 'electron'; +import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -25,6 +25,7 @@ import * as perf from 'vs/base/common/performance'; import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { getBackgroundColor } from 'vs/code/electron-main/theme'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { withNullAsUndefined } from 'vs/base/common/types'; import { endsWith } from 'vs/base/common/strings'; export interface IWindowCreationOptions { @@ -79,6 +80,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { private readonly touchBarGroups: Electron.TouchBarSegmentedControl[]; + private nodeless: boolean; + constructor( config: IWindowCreationOptions, @ILogService private readonly logService: ILogService, @@ -95,6 +98,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; + this.nodeless = !!(environmentService.args.nodeless && !environmentService.isBuilt); + // create browser window this.createBrowserWindow(config); @@ -124,7 +129,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { height: this.windowState.height, x: this.windowState.x, y: this.windowState.y, - backgroundColor: getBackgroundColor(this.stateService), + backgroundColor: this.nodeless ? undefined : getBackgroundColor(this.stateService), minWidth: CodeWindow.MIN_WIDTH, minHeight: CodeWindow.MIN_HEIGHT, show: !isFullscreenOrMaximized, @@ -138,6 +143,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { } }; + if (this.nodeless) { + options.webPreferences!.nodeIntegration = false; // simulate Electron 5 behaviour + } + if (isLinux) { options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) } @@ -192,6 +201,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } + if (this.nodeless) { + this._win.webContents.toggleDevTools(); + } + this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too } @@ -627,6 +640,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private doGetUrl(config: object): string { + if (this.nodeless) { + return `${require.toUrl('vs/code/electron-browser/workbench/workbench.nodeless.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; + } + return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; } @@ -692,55 +709,66 @@ export class CodeWindow extends Disposable implements ICodeWindow { private restoreWindowState(state?: IWindowState): IWindowState { if (state) { try { - state = this.validateWindowState(state); + state = withNullAsUndefined(this.validateWindowState(state)); } catch (err) { this.logService.warn(`Unexpected error validating window state: ${err}\n${err.stack}`); // somehow display API can be picky about the state to validate } } - return state || defaultWindowState(); + + if (!state) { + state = defaultWindowState(); + } + + return state; } - private validateWindowState(state: IWindowState): IWindowState | undefined { + private validateWindowState(state: IWindowState): IWindowState | null { + if (!state) { + return null; + } + if (typeof state.x !== 'number' || typeof state.y !== 'number' || typeof state.width !== 'number' || typeof state.height !== 'number' ) { - return undefined; + return null; } if (state.width <= 0 || state.height <= 0) { - return undefined; + return null; } const displays = screen.getAllDisplays(); // Single Monitor: be strict about x/y positioning if (displays.length === 1) { - const displayWorkingArea = this.getWorkingArea(displays[0]); - if (state.mode !== WindowMode.Maximized && displayWorkingArea) { - if (state.x < displayWorkingArea.x) { - state.x = displayWorkingArea.x; // prevent window from falling out of the screen to the left + const displayBounds = displays[0].bounds; + + // Careful with maximized: in that mode x/y can well be negative! + if (state.mode !== WindowMode.Maximized && displayBounds.width > 0 && displayBounds.height > 0 /* Linux X11 sessions sometimes report wrong display bounds */) { + if (state.x < displayBounds.x) { + state.x = displayBounds.x; // prevent window from falling out of the screen to the left } - if (state.y < displayWorkingArea.y) { - state.y = displayWorkingArea.y; // prevent window from falling out of the screen to the top + if (state.y < displayBounds.y) { + state.y = displayBounds.y; // prevent window from falling out of the screen to the top } - if (state.x > (displayWorkingArea.x + displayWorkingArea.width)) { - state.x = displayWorkingArea.x; // prevent window from falling out of the screen to the right + if (state.x > (displayBounds.x + displayBounds.width)) { + state.x = displayBounds.x; // prevent window from falling out of the screen to the right } - if (state.y > (displayWorkingArea.y + displayWorkingArea.height)) { - state.y = displayWorkingArea.y; // prevent window from falling out of the screen to the bottom + if (state.y > (displayBounds.y + displayBounds.height)) { + state.y = displayBounds.y; // prevent window from falling out of the screen to the bottom } - if (state.width > displayWorkingArea.width) { - state.width = displayWorkingArea.width; // prevent window from exceeding display bounds width + if (state.width > displayBounds.width) { + state.width = displayBounds.width; // prevent window from exceeding display bounds width } - if (state.height > displayWorkingArea.height) { - state.height = displayWorkingArea.height; // prevent window from exceeding display bounds height + if (state.height > displayBounds.height) { + state.height = displayBounds.height; // prevent window from exceeding display bounds height } } @@ -766,14 +794,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Multi Monitor (non-fullscreen): be less strict because metrics can be crazy const bounds = { x: state.x, y: state.y, width: state.width, height: state.height }; const display = screen.getDisplayMatching(bounds); - const displayWorkingArea = this.getWorkingArea(display); if ( - display && // we have a display matching the desired bounds - displayWorkingArea && // we have valid working area bounds - bounds.x < displayWorkingArea.x + displayWorkingArea.width && // prevent window from falling out of the screen to the right - bounds.y < displayWorkingArea.y + displayWorkingArea.height && // prevent window from falling out of the screen to the bottom - bounds.x + bounds.width > displayWorkingArea.x && // prevent window from falling out of the screen to the left - bounds.y + bounds.height > displayWorkingArea.y // prevent window from falling out of the scree nto the top + display && // we have a display matching the desired bounds + bounds.x < display.bounds.x + display.bounds.width && // prevent window from falling out of the screen to the right + bounds.y < display.bounds.y + display.bounds.height && // prevent window from falling out of the screen to the bottom + bounds.x + bounds.width > display.bounds.x && // prevent window from falling out of the screen to the left + bounds.y + bounds.height > display.bounds.y // prevent window from falling out of the scree nto the top ) { if (state.mode === WindowMode.Maximized) { const defaults = defaultWindowState(WindowMode.Maximized); // when maximized, make sure we have good values when the user restores the window @@ -786,25 +812,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { return state; } - return undefined; - } - - private getWorkingArea(display: Display): Rectangle | undefined { - - // Prefer the working area of the display to account for taskbars on the - // desktop being positioned somewhere (https://github.com/Microsoft/vscode/issues/50830). - // - // Linux X11 sessions sometimes report wrong display bounds, so we validate - // the reported sizes are positive. - if (display.workArea.width > 0 && display.workArea.height > 0) { - return display.workArea; - } - - if (display.bounds.width > 0 && display.bounds.height > 0) { - return display.bounds; - } - - return undefined; + return null; } getBounds(): Electron.Rectangle { diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index ca3e1f3490..a3a1971787 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -112,10 +112,6 @@ export class Main { private async installExtensions(extensions: string[], force: boolean): Promise { const failed: string[] = []; const installedExtensionsManifests: IExtensionManifest[] = []; - if (extensions.length) { - console.log(localize('installingExtensions', "Installing extensions...")); - } - for (const extension of extensions) { try { const manifest = await this.installExtension(extension, force); @@ -146,11 +142,11 @@ export class Main { if (valid) { return this.extensionManagementService.install(URI.file(extension)).then(id => { - console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(extension))); + console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed!", getBaseLabel(extension))); return manifest; }, error => { if (isPromiseCanceledError(error)) { - console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", getBaseLabel(extension))); + console.log(localize('cancelVsixInstall', "Cancelled installing Extension '{0}'.", getBaseLabel(extension))); return null; } else { return Promise.reject(error); @@ -195,7 +191,9 @@ export class Main { console.log(localize('forceUpdate', "Extension '{0}' v{1} is already installed, but a newer version {2} is available in the marketplace. Use '--force' option to update to newer version.", id, installedExtension.manifest.version, extension.version)); return Promise.resolve(null); } - console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, extension.version)); + console.log(localize('updateMessage', "Updating the Extension '{0}' to the version {1}", id, extension.version)); + } else { + console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); } await this.installFromGallery(id, extension); return manifest; @@ -212,7 +210,7 @@ export class Main { const newer = installedExtensions.filter(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version))[0]; if (newer && !force) { - console.log(localize('forceDowngrade', "A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version)); + console.log(localize('forceDowngrade', "A newer version of this extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version)); return false; } @@ -220,14 +218,14 @@ export class Main { } private async installFromGallery(id: string, extension: IGalleryExtension): Promise { - console.log(localize('installing', "Installing extension '{0}' v{1}...", id, extension.version)); + console.log(localize('installing', "Installing...")); try { await this.extensionManagementService.installFromGallery(extension); - console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, extension.version)); + console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version)); } catch (error) { if (isPromiseCanceledError(error)) { - console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", id)); + console.log(localize('cancelVsixInstall', "Cancelled installing Extension '{0}'.", id)); } else { throw error; } diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index 80ab30eb96..59a0955e6e 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -7,16 +7,11 @@ import * as cp from 'child_process'; import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; import { isWindows } from 'vs/base/common/platform'; -import { ILogService } from 'vs/platform/log/common/log'; -function getUnixShellEnvironment(logService: ILogService): Promise { +function getUnixShellEnvironment(): Promise { const promise = new Promise((resolve, reject) => { const runAsNode = process.env['ELECTRON_RUN_AS_NODE']; - logService.trace('getUnixShellEnvironment#runAsNode', runAsNode); - const noAttach = process.env['ELECTRON_NO_ATTACH_CONSOLE']; - logService.trace('getUnixShellEnvironment#noAttach', noAttach); - const mark = generateUuid().replace(/-/g, '').substr(0, 12); const regex = new RegExp(mark + '(.*)' + mark); @@ -26,9 +21,6 @@ function getUnixShellEnvironment(logService: ILogService): Promise; * This should only be done when Code itself is not launched * from within a shell. */ -export function getShellEnvironment(logService: ILogService): Promise { +export function getShellEnvironment(): Promise { if (_shellEnv === undefined) { if (isWindows) { - logService.trace('getShellEnvironment: runing on windows, skipping'); _shellEnv = Promise.resolve({}); } else if (process.env['VSCODE_CLI'] === '1') { - logService.trace('getShellEnvironment: runing on CLI, skipping'); _shellEnv = Promise.resolve({}); } else { - logService.trace('getShellEnvironment: running on Unix'); - _shellEnv = getUnixShellEnvironment(logService); + _shellEnv = getUnixShellEnvironment(); } } diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index 0f2f3327c0..39c9edf0e5 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -301,13 +301,13 @@ export namespace CoreNavigationCommands { export const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveTo', inSelectionMode: false, - precondition: undefined + precondition: null })); export const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveToSelect', inSelectionMode: true, - precondition: undefined + precondition: null })); abstract class ColumnSelectCommand extends CoreEditorCommand { @@ -330,7 +330,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'columnSelect', - precondition: undefined + precondition: null }); } @@ -354,7 +354,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorColumnSelectLeft', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -373,7 +373,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorColumnSelectRight', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -405,7 +405,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: false, id: 'cursorColumnSelectUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -417,7 +417,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: true, id: 'cursorColumnSelectPageUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -443,7 +443,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: false, id: 'cursorColumnSelectDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -455,7 +455,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: true, id: 'cursorColumnSelectPageDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -468,7 +468,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorMove', - precondition: undefined, + precondition: null, description: CursorMove_.description }); } @@ -531,7 +531,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorLeft', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -548,7 +548,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorLeftSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -564,7 +564,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorRight', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -581,7 +581,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorRightSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -597,7 +597,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -614,7 +614,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorUpSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -633,7 +633,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -649,7 +649,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageUpSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -665,7 +665,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -682,7 +682,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorDownSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -701,7 +701,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -717,7 +717,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageDownSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -729,7 +729,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'createCursor', - precondition: undefined + precondition: null }); } @@ -790,7 +790,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: '_lastCursorMoveToSelect', - precondition: undefined + precondition: null }); } @@ -835,7 +835,7 @@ export namespace CoreNavigationCommands { export const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: false, id: 'cursorHome', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -847,7 +847,7 @@ export namespace CoreNavigationCommands { export const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: true, id: 'cursorHomeSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -860,7 +860,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorLineStart', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -914,7 +914,7 @@ export namespace CoreNavigationCommands { export const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: false, id: 'cursorEnd', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -926,7 +926,7 @@ export namespace CoreNavigationCommands { export const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: true, id: 'cursorEndSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -939,7 +939,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorLineEnd', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -994,7 +994,7 @@ export namespace CoreNavigationCommands { export const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: false, id: 'cursorTop', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1006,7 +1006,7 @@ export namespace CoreNavigationCommands { export const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: true, id: 'cursorTopSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1038,7 +1038,7 @@ export namespace CoreNavigationCommands { export const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: false, id: 'cursorBottom', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1050,7 +1050,7 @@ export namespace CoreNavigationCommands { export const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: true, id: 'cursorBottomSelect', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1063,7 +1063,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'editorScroll', - precondition: undefined, + precondition: null, description: EditorScroll_.description }); } @@ -1134,7 +1134,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollLineUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1159,7 +1159,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollPageUp', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1185,7 +1185,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollLineDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1210,7 +1210,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollPageDown', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1257,20 +1257,20 @@ export namespace CoreNavigationCommands { export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: false, id: '_wordSelect', - precondition: undefined + precondition: null })); export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: true, id: '_wordSelectDrag', - precondition: undefined + precondition: null })); export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'lastCursorWordSelect', - precondition: undefined + precondition: null }); } @@ -1317,13 +1317,13 @@ export namespace CoreNavigationCommands { export const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: false, id: '_lineSelect', - precondition: undefined + precondition: null })); export const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: true, id: '_lineSelectDrag', - precondition: undefined + precondition: null })); class LastCursorLineCommand extends CoreEditorCommand { @@ -1353,20 +1353,20 @@ export namespace CoreNavigationCommands { export const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: false, id: 'lastCursorLineSelect', - precondition: undefined + precondition: null })); export const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: true, id: 'lastCursorLineSelectDrag', - precondition: undefined + precondition: null })); export const ExpandLineSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'expandLineSelection', - precondition: undefined, + precondition: null, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1445,7 +1445,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'revealLine', - precondition: undefined, + precondition: null, description: RevealLine_.description }); } @@ -1493,7 +1493,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'selectAll', - precondition: undefined + precondition: null }); } @@ -1513,7 +1513,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'setSelection', - precondition: undefined + precondition: null }); } @@ -1728,7 +1728,7 @@ class EditorHandlerCommand extends Command { constructor(id: string, handlerId: string, description?: ICommandHandlerDescription) { super({ id: id, - precondition: undefined, + precondition: null, description: description }); this._handlerId = handlerId; diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index ab0c4717e6..23141923ad 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -40,17 +40,17 @@ export interface ICommandMenubarOptions { } export interface ICommandOptions { id: string; - precondition: ContextKeyExpr | undefined; - kbOpts?: ICommandKeybindingsOptions; + precondition: ContextKeyExpr | null; + kbOpts?: ICommandKeybindingsOptions | null; description?: ICommandHandlerDescription; menubarOpts?: ICommandMenubarOptions; } export abstract class Command { public readonly id: string; - public readonly precondition: ContextKeyExpr | undefined; - private readonly _kbOpts: ICommandKeybindingsOptions | undefined; - private readonly _menubarOpts: ICommandMenubarOptions | undefined; - private readonly _description: ICommandHandlerDescription | undefined; + public readonly precondition: ContextKeyExpr | null; + private readonly _kbOpts: ICommandKeybindingsOptions | null | undefined; + private readonly _menubarOpts: ICommandMenubarOptions | null | undefined; + private readonly _description: ICommandHandlerDescription | null | undefined; constructor(opts: ICommandOptions) { this.id = opts.id; diff --git a/src/vs/editor/common/services/getIconClasses.ts b/src/vs/editor/common/services/getIconClasses.ts index 3a9ea2e795..9854146d45 100644 --- a/src/vs/editor/common/services/getIconClasses.ts +++ b/src/vs/editor/common/services/getIconClasses.ts @@ -19,11 +19,14 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe // Get the path and name of the resource. For data-URIs, we need to parse specially let name: string | undefined; + let path: string | undefined; if (resource.scheme === Schemas.data) { const metadata = DataUri.parseMetaData(resource); name = metadata.get(DataUri.META_DATA_LABEL); + path = name; } else { name = cssEscape(basenameOrAuthority(resource).toLowerCase()); + path = resource.path.toLowerCase(); } // Folders @@ -44,60 +47,46 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe classes.push(`ext-file-icon`); // extra segment to increase file-ext score } - // Detected Mode - const detectedModeId = detectModeId(modelService, modeService, resource); - if (detectedModeId) { - classes.push(`${cssEscape(detectedModeId)}-lang-file-icon`); + // Configured Language + let configuredLangId: string | null = getConfiguredLangId(modelService, modeService, resource); + configuredLangId = configuredLangId || (path ? modeService.getModeIdByFilepathOrFirstLine(path) : null); + if (configuredLangId) { + classes.push(`${cssEscape(configuredLangId)}-lang-file-icon`); } } } return classes; } -export function detectModeId(modelService: IModelService, modeService: IModeService, resource: uri): string | null { - if (!resource) { - return null; // we need a resource at least - } +export function getConfiguredLangId(modelService: IModelService, modeService: IModeService, resource: uri): string | null { + let configuredLangId: string | null = null; + if (resource) { + let modeId: string | null = null; - let modeId: string | null = null; + // Data URI: check for encoded metadata + if (resource.scheme === Schemas.data) { + const metadata = DataUri.parseMetaData(resource); + const mime = metadata.get(DataUri.META_DATA_MIME); - // Data URI: check for encoded metadata - if (resource.scheme === Schemas.data) { - const metadata = DataUri.parseMetaData(resource); - const mime = metadata.get(DataUri.META_DATA_MIME); + if (mime) { + modeId = modeService.getModeId(mime); + } + } - if (mime) { - modeId = modeService.getModeId(mime); + // Any other URI: check for model if existing + else { + const model = modelService.getModel(resource); + if (model) { + modeId = model.getLanguageIdentifier().language; + } + } + + if (modeId && modeId !== PLAINTEXT_MODE_ID) { + configuredLangId = modeId; // only take if the mode is specific (aka no just plain text) } } - // Any other URI: check for model if existing - else { - const model = modelService.getModel(resource); - if (model) { - modeId = model.getModeId(); - } - } - - // only take if the mode is specific (aka no just plain text) - if (modeId && modeId !== PLAINTEXT_MODE_ID) { - return modeId; - } - - // otherwise fallback to path based detection - let path: string | undefined; - if (resource.scheme === Schemas.data) { - const metadata = DataUri.parseMetaData(resource); - path = metadata.get(DataUri.META_DATA_LABEL); - } else { - path = resource.path.toLowerCase(); - } - - if (path) { - return modeService.getModeIdByFilepathOrFirstLine(path); - } - - return null; // finally - we do not know the mode id + return configuredLangId; } export function cssEscape(val: string): string { diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index 9c8539f62b..3c6cf0fdd8 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -5,7 +5,7 @@ import { IDisposable, IReference } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { ITextModel, ITextSnapshot } from 'vs/editor/common/model'; +import { ITextModel } from 'vs/editor/common/model'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -46,12 +46,6 @@ export interface ITextEditorModel extends IEditorModel { */ readonly textEditorModel: ITextModel | null; - /** - * Creates a snapshot of the model's contents. - */ - createSnapshot(this: IResolvedTextEditorModel): ITextSnapshot; - createSnapshot(this: ITextEditorModel): ITextSnapshot | null; - isReadonly(): boolean; } diff --git a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts index 5c778c4e82..bd719e9729 100644 --- a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts @@ -31,7 +31,7 @@ class JumpToBracketAction extends EditorAction { id: 'editor.action.jumpToBracket', label: nls.localize('smartSelect.jumpBracket', "Go to Bracket"), alias: 'Go to Bracket', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKSLASH, @@ -55,7 +55,7 @@ class SelectToBracketAction extends EditorAction { id: 'editor.action.selectToBracket', label: nls.localize('smartSelect.selectToBracket', "Select to Bracket"), alias: 'Select to Bracket', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index f736226271..f8264c769f 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -59,7 +59,7 @@ abstract class ExecCommandAction extends EditorAction { class ExecCommandCutAction extends ExecCommandAction { constructor() { - let kbOpts: ICommandKeybindingsOptions | undefined = { + let kbOpts: ICommandKeybindingsOptions | null = { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_X, win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_X, secondary: [KeyMod.Shift | KeyCode.Delete] }, @@ -68,7 +68,7 @@ class ExecCommandCutAction extends ExecCommandAction { // Do not bind cut keybindings in the browser, // since browsers do that for us and it avoids security prompts if (!platform.isNative) { - kbOpts = undefined; + kbOpts = null; } super('cut', { id: 'editor.action.clipboardCutAction', @@ -107,7 +107,7 @@ class ExecCommandCutAction extends ExecCommandAction { class ExecCommandCopyAction extends ExecCommandAction { constructor() { - let kbOpts: ICommandKeybindingsOptions | undefined = { + let kbOpts: ICommandKeybindingsOptions | null = { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_C, win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyCode.Insert] }, @@ -116,14 +116,14 @@ class ExecCommandCopyAction extends ExecCommandAction { // Do not bind copy keybindings in the browser, // since browsers do that for us and it avoids security prompts if (!platform.isNative) { - kbOpts = undefined; + kbOpts = null; } super('copy', { id: 'editor.action.clipboardCopyAction', label: nls.localize('actions.clipboard.copyLabel', "Copy"), alias: 'Copy', - precondition: undefined, + precondition: null, kbOpts: kbOpts, menuOpts: { group: CLIPBOARD_CONTEXT_MENU_GROUP, @@ -162,7 +162,7 @@ class ExecCommandCopyAction extends ExecCommandAction { class ExecCommandPasteAction extends ExecCommandAction { constructor() { - let kbOpts: ICommandKeybindingsOptions | undefined = { + let kbOpts: ICommandKeybindingsOptions | null = { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_V, win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] }, @@ -171,7 +171,7 @@ class ExecCommandPasteAction extends ExecCommandAction { // Do not bind paste keybindings in the browser, // since browsers do that for us and it avoids security prompts if (!platform.isNative) { - kbOpts = undefined; + kbOpts = null; } super('paste', { @@ -201,7 +201,7 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction { id: 'editor.action.clipboardCopyWithSyntaxHighlightingAction', label: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', "Copy With Syntax Highlighting"), alias: 'Copy With Syntax Highlighting', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index 367df28c44..64953ed807 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -34,8 +34,8 @@ export class CodeActionSet { public readonly actions: readonly CodeAction[]; - public constructor(actions: readonly CodeAction[]) { - this.actions = mergeSort([...actions], CodeActionSet.codeActionsComparator); + public constructor(actions: CodeAction[]) { + this.actions = mergeSort(actions, CodeActionSet.codeActionsComparator); } public get hasAutoFix() { diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 697f8979d2..2c19e2d7e4 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -176,7 +176,6 @@ function showCodeActionsForEditorSelection( return; } - MessageController.get(editor).closeMessage(); const pos = editor.getPosition(); controller.triggerFromEditorSelection(filter, autoApply).then(codeActions => { if (!codeActions || !codeActions.actions.length) { diff --git a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts index c641c9ce13..d5515688a5 100644 --- a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts +++ b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts @@ -20,12 +20,8 @@ export class CodeActionKind { public readonly value: string ) { } - public equals(other: CodeActionKind): boolean { - return this.value === other.value; - } - public contains(other: CodeActionKind): boolean { - return this.equals(other) || startsWith(other.value, this.value + CodeActionKind.sep); + return this.value === other.value || startsWith(other.value, this.value + CodeActionKind.sep); } public intersects(other: CodeActionKind): boolean { diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index 40f51d379c..b1ebfaa12f 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -76,9 +76,9 @@ export class ColorDetector implements IEditorContribution { } const languageId = model.getLanguageIdentifier(); // handle deprecated settings. [languageId].colorDecorators.enable - const deprecatedConfig = this._configurationService.getValue<{}>(languageId.language); + let deprecatedConfig = this._configurationService.getValue(languageId.language); if (deprecatedConfig) { - const colorDecorators = deprecatedConfig['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable'); + let colorDecorators = deprecatedConfig['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable'); if (colorDecorators && colorDecorators['enable'] !== undefined && !colorDecorators['enable']) { return colorDecorators['enable']; } diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index a77302fc2e..d6c2cb1595 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { IAction } from 'vs/base/common/actions'; import { KeyCode, KeyMod, ResolvedKeybinding } from 'vs/base/common/keyCodes'; @@ -176,18 +176,18 @@ export class ContextMenuController implements IEditorContribution { getActions: () => actions, - getActionViewItem: (action) => { + getActionItem: (action) => { const keybinding = this._keybindingFor(action); if (keybinding) { - return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel(), isMenu: true }); + return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel(), isMenu: true }); } - const customActionViewItem = action; - if (typeof customActionViewItem.getActionViewItem === 'function') { - return customActionViewItem.getActionViewItem(); + const customActionItem = action; + if (typeof customActionItem.getActionItem === 'function') { + return customActionItem.getActionItem(); } - return new ActionViewItem(action, action, { icon: true, label: true, isMenu: true }); + return new ActionItem(action, action, { icon: true, label: true, isMenu: true }); }, getKeyBinding: (action): ResolvedKeybinding | undefined => { @@ -228,7 +228,7 @@ class ShowContextMenu extends EditorAction { id: 'editor.action.showContextMenu', label: nls.localize('action.showContextMenu.label', "Show Editor Context Menu"), alias: 'Show Editor Context Menu', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.Shift | KeyCode.F10, diff --git a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts index 29b81d9ee8..59225a9be0 100644 --- a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts +++ b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts @@ -119,7 +119,7 @@ export class CursorUndo extends EditorAction { id: 'cursorUndo', label: nls.localize('cursor.undo', "Soft Undo"), alias: 'Soft Undo', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_U, diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index 0b8cad0358..5f7c2df44f 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -422,7 +422,7 @@ export class StartFindAction extends EditorAction { id: FIND_IDS.StartFindAction, label: nls.localize('startFindAction', "Find"), alias: 'Find', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_F, @@ -459,7 +459,7 @@ export class StartFindWithSelectionAction extends EditorAction { id: FIND_IDS.StartFindWithSelection, label: nls.localize('startFindWithSelectionAction', "Find With Selection"), alias: 'Find With Selection', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: null, primary: 0, @@ -513,7 +513,7 @@ export class NextMatchFindAction extends MatchFindAction { id: FIND_IDS.NextMatchFindAction, label: nls.localize('findNextMatchAction', "Find Next"), alias: 'Find Next', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyCode.F3, @@ -535,7 +535,7 @@ export class PreviousMatchFindAction extends MatchFindAction { id: FIND_IDS.PreviousMatchFindAction, label: nls.localize('findPreviousMatchAction', "Find Previous"), alias: 'Find Previous', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyCode.F3, @@ -583,7 +583,7 @@ export class NextSelectionMatchFindAction extends SelectionMatchFindAction { id: FIND_IDS.NextSelectionMatchFindAction, label: nls.localize('nextSelectionMatchFindAction', "Find Next Selection"), alias: 'Find Next Selection', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.F3, @@ -604,7 +604,7 @@ export class PreviousSelectionMatchFindAction extends SelectionMatchFindAction { id: FIND_IDS.PreviousSelectionMatchFindAction, label: nls.localize('previousSelectionMatchFindAction', "Find Previous Selection"), alias: 'Find Previous Selection', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F3, @@ -625,7 +625,7 @@ export class StartFindReplaceAction extends EditorAction { id: FIND_IDS.StartFindReplaceAction, label: nls.localize('startReplace', "Replace"), alias: 'Replace', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_H, @@ -704,7 +704,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleCaseSensitiveCommand, - precondition: undefined, + precondition: null, handler: x => x.toggleCaseSensitive(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -718,7 +718,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleWholeWordCommand, - precondition: undefined, + precondition: null, handler: x => x.toggleWholeWords(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -732,7 +732,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleRegexCommand, - precondition: undefined, + precondition: null, handler: x => x.toggleRegex(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -746,7 +746,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleSearchScopeCommand, - precondition: undefined, + precondition: null, handler: x => x.toggleSearchScope(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index 9ec22649c4..ab52ff724e 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -503,7 +503,7 @@ class UnfoldAction extends FoldingAction { id: 'editor.unfold', label: nls.localize('unfoldAction.label', "Unfold"), alias: 'Unfold', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET, @@ -567,7 +567,7 @@ class UnFoldRecursivelyAction extends FoldingAction { id: 'editor.unfoldRecursively', label: nls.localize('unFoldRecursivelyAction.label', "Unfold Recursively"), alias: 'Unfold Recursively', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET), @@ -588,7 +588,7 @@ class FoldAction extends FoldingAction { id: 'editor.fold', label: nls.localize('foldAction.label', "Fold"), alias: 'Fold', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET, @@ -652,7 +652,7 @@ class FoldRecursivelyAction extends FoldingAction { id: 'editor.foldRecursively', label: nls.localize('foldRecursivelyAction.label', "Fold Recursively"), alias: 'Fold Recursively', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET), @@ -674,7 +674,7 @@ class FoldAllBlockCommentsAction extends FoldingAction { id: 'editor.foldAllBlockComments', label: nls.localize('foldAllBlockComments.label', "Fold All Block Comments"), alias: 'Fold All Block Comments', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_SLASH), @@ -707,7 +707,7 @@ class FoldAllRegionsAction extends FoldingAction { id: 'editor.foldAllMarkerRegions', label: nls.localize('foldAllMarkerRegions.label', "Fold All Regions"), alias: 'Fold All Regions', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_8), @@ -740,7 +740,7 @@ class UnfoldAllRegionsAction extends FoldingAction { id: 'editor.unfoldAllMarkerRegions', label: nls.localize('unfoldAllMarkerRegions.label', "Unfold All Regions"), alias: 'Unfold All Regions', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_9), @@ -773,7 +773,7 @@ class FoldAllAction extends FoldingAction { id: 'editor.foldAll', label: nls.localize('foldAllAction.label', "Fold All"), alias: 'Fold All', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_0), @@ -794,7 +794,7 @@ class UnfoldAllAction extends FoldingAction { id: 'editor.unfoldAll', label: nls.localize('unfoldAllAction.label', "Unfold All"), alias: 'Unfold All', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_J), @@ -838,7 +838,7 @@ for (let i = 1; i <= 7; i++) { id: FoldLevelAction.ID(i), label: nls.localize('foldLevelAction.label', "Fold Level {0}", i), alias: `Fold Level ${i}`, - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | (KeyCode.KEY_0 + i)), diff --git a/src/vs/editor/contrib/fontZoom/fontZoom.ts b/src/vs/editor/contrib/fontZoom/fontZoom.ts index bee8d01a4d..4076d02fab 100644 --- a/src/vs/editor/contrib/fontZoom/fontZoom.ts +++ b/src/vs/editor/contrib/fontZoom/fontZoom.ts @@ -15,7 +15,7 @@ class EditorFontZoomIn extends EditorAction { id: 'editor.action.fontZoomIn', label: nls.localize('EditorFontZoomIn.label', "Editor Font Zoom In"), alias: 'Editor Font Zoom In', - precondition: undefined + precondition: null }); } @@ -31,7 +31,7 @@ class EditorFontZoomOut extends EditorAction { id: 'editor.action.fontZoomOut', label: nls.localize('EditorFontZoomOut.label', "Editor Font Zoom Out"), alias: 'Editor Font Zoom Out', - precondition: undefined + precondition: null }); } @@ -47,7 +47,7 @@ class EditorFontZoomReset extends EditorAction { id: 'editor.action.fontZoomReset', label: nls.localize('EditorFontZoomReset.label', "Editor Font Zoom Reset"), alias: 'Editor Font Zoom Reset', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts index f8f3ea32d3..6d2b86c198 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts @@ -294,7 +294,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC private gotoDefinition(target: IMouseTarget, sideBySide: boolean): Promise { this.editor.setPosition(target.position!); - const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: '', label: '', id: '', precondition: undefined }); + const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: '', label: '', id: '', precondition: null }); return this.editor.invokeWithinContext(accessor => action.run(accessor, this.editor)); } diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index bca65f0fa7..fef2d75cda 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -251,7 +251,7 @@ class ShowHoverAction extends EditorAction { ] }, "Show Hover"), alias: 'Show Hover', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_I), diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 966de575cc..927abc1576 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -40,6 +40,7 @@ import { applyCodeAction, QuickFixAction } from 'vs/editor/contrib/codeAction/co import { Action } from 'vs/base/common/actions'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IModeService } from 'vs/editor/common/services/modeService'; +import { withNullAsUndefined } from 'vs/base/common/types'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; const $ = dom.$; @@ -67,13 +68,14 @@ class ModesContentComputer implements IHoverComputer { private readonly _editor: ICodeEditor; private _result: HoverPart[]; - private _range?: Range; + private _range: Range | null; constructor( editor: ICodeEditor, private readonly _markerDecorationsService: IMarkerDecorationsService ) { this._editor = editor; + this._range = null; } setRange(range: Range): void { @@ -181,7 +183,7 @@ class ModesContentComputer implements IHoverComputer { private _getLoadingMessage(): HoverPart { return { - range: this._range, + range: withNullAsUndefined(this._range), contents: [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))] }; } diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index 4b89666da4..d6d228993f 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -253,7 +253,7 @@ export class IndentUsingTabs extends ChangeIndentationSizeAction { id: IndentUsingTabs.ID, label: nls.localize('indentUsingTabs', "Indent Using Tabs"), alias: 'Indent Using Tabs', - precondition: undefined + precondition: null }); } } @@ -267,7 +267,7 @@ export class IndentUsingSpaces extends ChangeIndentationSizeAction { id: IndentUsingSpaces.ID, label: nls.localize('indentUsingSpaces', "Indent Using Spaces"), alias: 'Indent Using Spaces', - precondition: undefined + precondition: null }); } } @@ -281,7 +281,7 @@ export class DetectIndentation extends EditorAction { id: DetectIndentation.ID, label: nls.localize('detectIndentation', "Detect Indentation from Content"), alias: 'Detect Indentation from Content', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index f4aee3992f..a7828fee15 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -410,7 +410,7 @@ class OpenLinkAction extends EditorAction { id: 'editor.action.openLink', label: nls.localize('label', "Open Link"), alias: 'Open Link', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts index 1a5fd8d53a..e3df2168f1 100644 --- a/src/vs/editor/contrib/message/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -35,7 +35,7 @@ export class MessageController extends Disposable implements editorCommon.IEdito private readonly _editor: ICodeEditor; private readonly _visible: IContextKey; - private _messageWidget?: MessageWidget; + private _messageWidget: MessageWidget; private _messageListeners: IDisposable[] = []; constructor( @@ -96,9 +96,7 @@ export class MessageController extends Disposable implements editorCommon.IEdito closeMessage(): void { this._visible.reset(); this._messageListeners = dispose(this._messageListeners); - if (this._messageWidget) { - this._messageListeners.push(MessageWidget.fadeOut(this._messageWidget)); - } + this._messageListeners.push(MessageWidget.fadeOut(this._messageWidget)); } private _onDidAttemptReadOnlyEdit(): void { diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index b500bd94d1..4b1b71014b 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -34,7 +34,7 @@ export class InsertCursorAbove extends EditorAction { id: 'editor.action.insertCursorAbove', label: nls.localize('mutlicursor.insertAbove', "Add Cursor Above"), alias: 'Add Cursor Above', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.UpArrow, @@ -83,7 +83,7 @@ export class InsertCursorBelow extends EditorAction { id: 'editor.action.insertCursorBelow', label: nls.localize('mutlicursor.insertBelow', "Add Cursor Below"), alias: 'Add Cursor Below', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.DownArrow, @@ -132,7 +132,7 @@ class InsertCursorAtEndOfEachLineSelected extends EditorAction { id: 'editor.action.insertCursorAtEndOfEachLineSelected', label: nls.localize('mutlicursor.insertAtEndOfEachLineSelected', "Add Cursors to Line Ends"), alias: 'Add Cursors to Line Ends', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_I, @@ -184,7 +184,7 @@ class InsertCursorAtEndOfLineSelected extends EditorAction { id: 'editor.action.addCursorsToBottom', label: nls.localize('mutlicursor.addCursorsToBottom', "Add Cursors To Bottom"), alias: 'Add Cursors To Bottom', - precondition: undefined + precondition: null }); } @@ -214,7 +214,7 @@ class InsertCursorAtTopOfLineSelected extends EditorAction { id: 'editor.action.addCursorsToTop', label: nls.localize('mutlicursor.addCursorsToTop', "Add Cursors To Top"), alias: 'Add Cursors To Top', - precondition: undefined + precondition: null }); } @@ -650,7 +650,7 @@ export class AddSelectionToNextFindMatchAction extends MultiCursorSelectionContr id: 'editor.action.addSelectionToNextFindMatch', label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), alias: 'Add Selection To Next Find Match', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.KEY_D, @@ -675,7 +675,7 @@ export class AddSelectionToPreviousFindMatchAction extends MultiCursorSelectionC id: 'editor.action.addSelectionToPreviousFindMatch', label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), alias: 'Add Selection To Previous Find Match', - precondition: undefined, + precondition: null, menubarOpts: { menuId: MenuId.MenubarSelectionMenu, group: '3_multi', @@ -695,7 +695,7 @@ export class MoveSelectionToNextFindMatchAction extends MultiCursorSelectionCont id: 'editor.action.moveSelectionToNextFindMatch', label: nls.localize('moveSelectionToNextFindMatch', "Move Last Selection To Next Find Match"), alias: 'Move Last Selection To Next Find Match', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D), @@ -714,7 +714,7 @@ export class MoveSelectionToPreviousFindMatchAction extends MultiCursorSelection id: 'editor.action.moveSelectionToPreviousFindMatch', label: nls.localize('moveSelectionToPreviousFindMatch', "Move Last Selection To Previous Find Match"), alias: 'Move Last Selection To Previous Find Match', - precondition: undefined + precondition: null }); } protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { @@ -728,7 +728,7 @@ export class SelectHighlightsAction extends MultiCursorSelectionControllerAction id: 'editor.action.selectHighlights', label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), alias: 'Select All Occurrences of Find Match', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L, diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 2d2bf8140e..8624cd30f6 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -161,7 +161,7 @@ class GrowSelectionAction extends AbstractSmartSelect { id: 'editor.action.smartSelect.expand', label: nls.localize('smartSelect.expand', "Expand Selection"), alias: 'Expand Selection', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow, @@ -187,7 +187,7 @@ class ShrinkSelectionAction extends AbstractSmartSelect { id: 'editor.action.smartSelect.shrink', label: nls.localize('smartSelect.shrink', "Shrink Selection"), alias: 'Shrink Selection', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow, diff --git a/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts b/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts index 3498ee790e..94c9a238c1 100644 --- a/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts +++ b/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts @@ -20,7 +20,7 @@ export class ToggleTabFocusModeAction extends EditorAction { id: ToggleTabFocusModeAction.ID, label: nls.localize({ key: 'toggle.tabMovesFocus', comment: ['Turn on/off use of tab key for moving focus around VS Code'] }, "Toggle Tab Key Moves Focus"), alias: 'Toggle Tab Key Moves Focus', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_M, diff --git a/src/vs/editor/contrib/tokenization/tokenization.ts b/src/vs/editor/contrib/tokenization/tokenization.ts index c193e268fa..3dcbe172ae 100644 --- a/src/vs/editor/contrib/tokenization/tokenization.ts +++ b/src/vs/editor/contrib/tokenization/tokenization.ts @@ -14,7 +14,7 @@ class ForceRetokenizeAction extends EditorAction { id: 'editor.action.forceRetokenize', label: nls.localize('forceRetokenize', "Developer: Force Retokenize"), alias: 'Developer: Force Retokenize', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index b45f176a7b..a961cbc712 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -98,7 +98,7 @@ export class CursorWordStartLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartLeft', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.LeftArrow, @@ -115,7 +115,7 @@ export class CursorWordEndLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndLeft', - precondition: undefined + precondition: null }); } } @@ -126,7 +126,7 @@ export class CursorWordLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeft', - precondition: undefined + precondition: null }); } } @@ -137,7 +137,7 @@ export class CursorWordStartLeftSelect extends WordLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartLeftSelect', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow, @@ -154,7 +154,7 @@ export class CursorWordEndLeftSelect extends WordLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndLeftSelect', - precondition: undefined + precondition: null }); } } @@ -165,7 +165,7 @@ export class CursorWordLeftSelect extends WordLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordLeftSelect', - precondition: undefined + precondition: null }); } } @@ -176,7 +176,7 @@ export class CursorWordStartRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartRight', - precondition: undefined + precondition: null }); } } @@ -187,7 +187,7 @@ export class CursorWordEndRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndRight', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.RightArrow, @@ -204,7 +204,7 @@ export class CursorWordRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordRight', - precondition: undefined + precondition: null }); } } @@ -215,7 +215,7 @@ export class CursorWordStartRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartRightSelect', - precondition: undefined + precondition: null }); } } @@ -226,7 +226,7 @@ export class CursorWordEndRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndRightSelect', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow, @@ -243,7 +243,7 @@ export class CursorWordRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordRightSelect', - precondition: undefined + precondition: null }); } } diff --git a/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts index 36cd945fac..61a667116c 100644 --- a/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts +++ b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts @@ -79,7 +79,7 @@ export class CursorWordPartLeft extends WordPartLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordPartLeft', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -98,7 +98,7 @@ export class CursorWordPartLeftSelect extends WordPartLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordPartLeftSelect', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -122,7 +122,7 @@ export class CursorWordPartRight extends WordPartRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordPartRight', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -138,7 +138,7 @@ export class CursorWordPartRightSelect extends WordPartRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordPartRightSelect', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index 8685aa7826..ee0a123da6 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -330,7 +330,7 @@ class ShowAccessibilityHelpAction extends EditorAction { id: 'editor.action.showAccessibilityHelp', label: AccessibilityHelpNLS.showAccessibilityHelpAction, alias: 'Show Accessibility Help', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: (browser.isIE ? KeyMod.CtrlCmd | KeyCode.F1 : KeyMod.Alt | KeyCode.F1), diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index a581e0b8a1..63331082a6 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -84,7 +84,7 @@ class InspectTokens extends EditorAction { id: 'editor.action.inspectTokens', label: InspectTokensNLS.inspectTokensAction, alias: 'Developer: Inspect Tokens', - precondition: undefined + precondition: null }); } diff --git a/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts b/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts index 0a7e0414bb..701ac49c8d 100644 --- a/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts +++ b/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts @@ -149,7 +149,7 @@ export class GotoLineAction extends BaseEditorQuickOpenAction { id: 'editor.action.gotoLine', label: GoToLineNLS.gotoLineActionLabel, alias: 'Go to Line...', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.KEY_G, diff --git a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts index 8f1f0fbce7..2279303383 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts @@ -82,7 +82,7 @@ export class QuickCommandAction extends BaseEditorQuickOpenAction { id: 'editor.action.quickCommand', label: QuickCommandNLS.quickCommandActionLabel, alias: 'Command Palette', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: (browser.isIE ? KeyMod.Alt | KeyCode.F1 : KeyCode.F1), diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts index ffc0e34367..f8e059ab08 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts @@ -26,12 +26,12 @@ let SCOPE_PREFIX = ':'; export class SymbolEntry extends QuickOpenEntryGroup { private readonly name: string; private readonly type: string; - private readonly description: string | undefined; + private readonly description: string | null; private readonly range: Range; private readonly editor: ICodeEditor; private readonly decorator: IDecorator; - constructor(name: string, type: string, description: string | undefined, range: Range, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator) { + constructor(name: string, type: string, description: string | null, range: Range, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator) { super(); this.name = name; @@ -55,7 +55,7 @@ export class SymbolEntry extends QuickOpenEntryGroup { return this.type; } - public getDescription(): string | undefined { + public getDescription(): string | null { return this.description; } @@ -169,7 +169,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { }); } - private symbolEntry(name: string, type: string, description: string | undefined, range: IRange, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator): SymbolEntry { + private symbolEntry(name: string, type: string, description: string | null, range: IRange, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator): SymbolEntry { return new SymbolEntry(name, type, description, Range.lift(range), highlights, editor, decorator); } @@ -192,7 +192,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { if (highlights) { // Show parent scope as description - let description: string | undefined = undefined; + let description: string | null = null; if (element.containerName) { description = element.containerName; } diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index acfb20217b..a6b3223af4 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -19,7 +19,7 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { IPosition, Position as Pos } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { ITextModel, ITextSnapshot } from 'vs/editor/common/model'; +import { ITextModel } from 'vs/editor/common/model'; import { TextEdit, WorkspaceEdit, isResourceTextEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -67,10 +67,6 @@ export class SimpleModel implements IResolvedTextEditorModel { return this.model; } - public createSnapshot(): ITextSnapshot { - return this.model.createSnapshot(); - } - public isReadonly(): boolean { return false; } @@ -352,7 +348,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { if (!keybinding) { // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); + result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); } else { const resolvedKeybindings = this.resolveKeybinding(keybinding); for (const resolvedKeybinding of resolvedKeybindings) { diff --git a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts index 7bfb82fe07..8064f324c6 100644 --- a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts +++ b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts @@ -17,7 +17,7 @@ class ToggleHighContrast extends EditorAction { id: 'editor.action.toggleHighContrast', label: ToggleHighContrastNLS.toggleHighContrast, alias: 'Toggle High Contrast Theme', - precondition: undefined + precondition: null }); this._originalThemeName = null; } diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuItemActionItem.ts similarity index 90% rename from src/vs/platform/actions/browser/menuEntryActionViewItem.ts rename to src/vs/platform/actions/browser/menuItemActionItem.ts index 9100366c47..6f2d8cac33 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuItemActionItem.ts @@ -5,7 +5,7 @@ import { addClasses, createCSSRule, removeClasses } from 'vs/base/browser/dom'; import { domEvent } from 'vs/base/browser/event'; -import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAction } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; import { IdGenerator } from 'vs/base/common/idGenerator'; @@ -114,16 +114,16 @@ export function fillInActions(groups: [string, Array = new Map(); @@ -231,13 +231,13 @@ export class MenuEntryActionViewItem extends ActionViewItem { const iconPathMapKey = item.iconLocation.dark.toString(); - if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { - iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!; + if (MenuItemActionItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { + iconClass = MenuItemActionItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!; } else { iconClass = ids.nextId(); createCSSRule(`.icon.${iconClass}`, `background-image: url("${(item.iconLocation.light || item.iconLocation.dark).toString()}")`); createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${item.iconLocation.dark.toString()}")`); - MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); + MenuItemActionItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); } addClasses(this.label, 'icon', iconClass); @@ -255,10 +255,10 @@ export class MenuEntryActionViewItem extends ActionViewItem { } } -// Need to subclass MenuEntryActionViewItem in order to respect +// Need to subclass MenuItemActionItem in order to respect // the action context coming from any action bar, without breaking // existing users -export class ContextAwareMenuEntryActionViewItem extends MenuEntryActionViewItem { +export class ContextAwareMenuItemActionItem extends MenuItemActionItem { onClick(event: MouseEvent): void { event.preventDefault(); @@ -273,7 +273,7 @@ export class ContextAwareMenuEntryActionViewItem extends MenuEntryActionViewItem // Always show label for action items, instead of whether they don't have // an icon/CSS class. Useful for some toolbar scenarios in particular with // contributed actions from other extensions -export class LabeledMenuItemActionItem extends MenuEntryActionViewItem { +export class LabeledMenuItemActionItem extends MenuItemActionItem { private _labeledItemClassDispose: IDisposable; constructor( @@ -301,13 +301,13 @@ export class LabeledMenuItemActionItem extends MenuEntryActionViewItem { const iconPathMapKey = item.iconLocation.dark.toString(); - if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { - iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey); + if (MenuItemActionItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) { + iconClass = MenuItemActionItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey); } else { iconClass = ids.nextId(); createCSSRule(`.icon.${iconClass}`, `background-image: url("${(item.iconLocation.light || item.iconLocation.dark).toString()}")`); createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${item.iconLocation.dark.toString()}")`); - MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); + MenuItemActionItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass); } addClasses(this.label, 'icon', iconClass, this._defaultCSSClassToAdd); diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 396e49d6a8..ed0afc5e78 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -18,18 +18,21 @@ export interface ILocalizedString { original: string; } -export interface ICommandAction { +export interface IBaseCommandAction { id: string; title: string | ILocalizedString; category?: string | ILocalizedString; +} + +export interface ICommandAction extends IBaseCommandAction { iconLocation?: { dark: URI; light?: URI; }; precondition?: ContextKeyExpr; toggled?: ContextKeyExpr; } -type Serialized = { [K in keyof T]: T[K] extends URI ? UriComponents : Serialized }; - -export type ISerializableCommandAction = Serialized; +export interface ISerializableCommandAction extends IBaseCommandAction { + iconLocation?: { dark: UriComponents; light?: UriComponents; }; +} export interface IMenuItem { command: ICommandAction; diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 1d0f5c8bb6..c89e7d5559 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -73,7 +73,7 @@ export class ContextMenuHandler { actionRunner.onDidBeforeRun(this.onActionRun, this, menuDisposables); actionRunner.onDidRun(this.onDidActionRun, this, menuDisposables); menu = new Menu(container, actions, { - actionViewItemProvider: delegate.getActionViewItem, + actionItemProvider: delegate.getActionItem, context: delegate.getActionsContext ? delegate.getActionsContext() : null, actionRunner, getKeyBinding: delegate.getKeyBinding ? delegate.getKeyBinding : action => this.keybindingService.lookupKeybinding(action.id) diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 7f7a939264..476d02f4d4 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -186,8 +186,8 @@ class WindowDriver implements IWindowDriver { const lines: string[] = []; - for (let i = 0; i < xterm.buffer.length; i++) { - lines.push(xterm.buffer.getLine(i)!.translateToString(true)); + for (let i = 0; i < xterm._core.buffer.lines.length; i++) { + lines.push(xterm._core.buffer.translateBufferLineToString(i, true)); } return lines; diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 3b8d1d395f..4995e98882 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -63,7 +63,7 @@ export interface IBaseResourceInput { export interface IResourceInput extends IBaseResourceInput { /** - * The resource URI of the resource to open. + * The resource URL of the resource to open. */ resource: URI; @@ -71,12 +71,6 @@ export interface IResourceInput extends IBaseResourceInput { * The encoding of the text input if known. */ readonly encoding?: string; - - /** - * The identifier of the language mode of the text input - * if known to use when displaying the contents. - */ - readonly mode?: string; } export interface IEditorOptions { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 0ad08e381a..7271fa87bc 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -69,6 +69,7 @@ export interface ParsedArgs { 'driver'?: string; 'driver-verbose'?: boolean; remote?: string; + 'nodeless'?: boolean; // TODO@ben revisit electron5 nodeless support // {{SQL CARBON EDIT}} aad?: boolean; database?: string; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index e7b612ea04..97e7efb1bc 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -95,6 +95,8 @@ export const options: Option[] = [ { id: 'trace-category-filter', type: 'string' }, { id: 'trace-options', type: 'string' }, { id: 'prof-code-loading', type: 'boolean' }, + { id: 'nodeless', type: 'boolean' }, // TODO@ben revisit electron5 nodeless support + // {{SQL CARBON EDIT}} { id: 'database', type: 'string', alias: 'D' }, { id: 'server', type: 'string', alias: 'S' }, diff --git a/src/vs/platform/files/node/fileConstants.ts b/src/vs/platform/files/node/fileConstants.ts new file mode 100644 index 0000000000..9050d7d400 --- /dev/null +++ b/src/vs/platform/files/node/fileConstants.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// See https://github.com/Microsoft/vscode/issues/30180 +const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB +const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB + +// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149 +const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB +const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB + +export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE; +export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE; \ No newline at end of file diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 7788d772d1..5f8be81b21 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -299,11 +299,11 @@ export class HistoryMainService implements IHistoryMainService { description = nls.localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService)); args = `--folder-uri "${workspace.toString()}"`; } else { - description = nls.localize('workspaceDesc', "{0} {1}", getBaseLabel(workspace.configPath), getPathLabel(dirname(workspace.configPath), this.environmentService)); + description = nls.localize('codeWorkspace', "Code Workspace"); args = `--file-uri "${workspace.configPath.toString()}"`; } - return { + return { type: 'task', title, description, diff --git a/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts index 76e18d545f..9db9cab627 100644 --- a/src/vs/platform/instantiation/common/instantiation.ts +++ b/src/vs/platform/instantiation/common/instantiation.ts @@ -125,7 +125,7 @@ function storeServiceDependency(id: Function, target: Function, index: number, o /** * A *only* valid way to create a {{ServiceIdentifier}}. */ -export function createDecorator(serviceId: string): ServiceIdentifier { +export function createDecorator(serviceId: string): { (...args: any[]): void; type: T; } { if (_util.serviceIds.has(serviceId)) { return _util.serviceIds.get(serviceId)!; diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index e63be3ef21..7d71317230 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -221,7 +221,7 @@ export class InstantiationService implements IInstantiationService { // Return a proxy object that's backed by an idle value. That // strategy is to instantiate services in our idle time or when actually // needed but not when injected into a consumer - const idle = new IdleValue(() => this._createInstance(ctor, args, _trace)); + const idle = new IdleValue(() => this._createInstance(ctor, args, _trace)); return new Proxy(Object.create(null), { get(_target: T, prop: PropertyKey): any { return idle.getValue()[prop]; diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index e56e69cd7d..0f94f131ac 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -17,6 +17,7 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe import { INotificationService } from 'vs/platform/notification/common/notification'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { withNullAsUndefined } from 'vs/base/common/types'; interface CurrentChord { keypress: string; @@ -95,11 +96,11 @@ export abstract class AbstractKeybindingService extends Disposable implements IK } public lookupKeybinding(commandId: string): ResolvedKeybinding | undefined { - const result = this._getResolver().lookupPrimaryKeybinding(commandId); + let result = this._getResolver().lookupPrimaryKeybinding(commandId); if (!result) { return undefined; } - return result.resolvedKeybinding; + return withNullAsUndefined(result.resolvedKeybinding); } public dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean { diff --git a/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts b/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts index d4087f26bc..084a314b8e 100644 --- a/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts +++ b/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts @@ -10,7 +10,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class ResolvedKeybindingItem { _resolvedKeybindingItemBrand: void; - public readonly resolvedKeybinding: ResolvedKeybinding | undefined; + public readonly resolvedKeybinding: ResolvedKeybinding | null; public readonly keypressParts: string[]; public readonly bubble: boolean; public readonly command: string | null; @@ -18,7 +18,7 @@ export class ResolvedKeybindingItem { public readonly when: ContextKeyExpr | undefined; public readonly isDefault: boolean; - constructor(resolvedKeybinding: ResolvedKeybinding | undefined, command: string | null, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean) { + constructor(resolvedKeybinding: ResolvedKeybinding | null, command: string | null, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean) { this.resolvedKeybinding = resolvedKeybinding; this.keypressParts = resolvedKeybinding ? removeElementsAfterNulls(resolvedKeybinding.getDispatchParts()) : []; this.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false); diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index d477d1679c..b9f0405a7d 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -180,7 +180,7 @@ suite('AbstractKeybindingService', () => { }); function kbItem(keybinding: number, command: string, when?: ContextKeyExpr): ResolvedKeybindingItem { - const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); + const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : null); return new ResolvedKeybindingItem( resolvedKeybinding, command, diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index baa17f0af5..e44c624060 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -21,7 +21,7 @@ function createContext(ctx: any) { suite('KeybindingResolver', () => { function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem { - const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); + const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : null); return new ResolvedKeybindingItem( resolvedKeybinding, command, diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index a1aea75a55..01b56cdf92 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -266,7 +266,7 @@ export class WorkbenchList extends List { ...computeStyles(themeService.getTheme(), defaultListStyles), ...workbenchListOptions, horizontalScrolling - } + } as IListOptions ); this.disposables.push(workbenchListOptionsDisposable); @@ -348,7 +348,7 @@ export class WorkbenchPagedList extends PagedList { ...computeStyles(themeService.getTheme(), defaultListStyles), ...workbenchListOptions, horizontalScrolling - } + } as IListOptions ); this.disposables = [workbenchListOptionsDisposable]; @@ -689,7 +689,7 @@ export class TreeResourceNavigator2 extends Disposable { super(); this.options = { - ...{ + ...{ openOnSelection: true }, ...(options || {}) diff --git a/src/vs/platform/registry/common/platform.ts b/src/vs/platform/registry/common/platform.ts index 04c360723a..79a86a8baf 100644 --- a/src/vs/platform/registry/common/platform.ts +++ b/src/vs/platform/registry/common/platform.ts @@ -54,4 +54,4 @@ class RegistryImpl implements IRegistry { } } -export const Registry: IRegistry = new RegistryImpl(); +export const Registry = new RegistryImpl(); diff --git a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts index df41e95442..f5354472d1 100644 --- a/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts +++ b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, IFileChange, IFileSystemProvider, IStat, IWatchOptions, FileOpenOptions } from 'vs/platform/files/common/files'; +import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileChange, IFileSystemProvider, IStat, IWatchOptions } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { OperatingSystem } from 'vs/base/common/platform'; @@ -50,7 +50,7 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF setCaseSensitive(isCaseSensitive: boolean) { let capabilities = ( - FileSystemProviderCapabilities.FileOpenReadWriteClose + FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.FileFolderCopy ); @@ -68,28 +68,14 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF return this.channel.call('stat', [resource]); } - open(resource: URI, opts: FileOpenOptions): Promise { - return this.channel.call('open', [resource, opts]); + async readFile(resource: URI): Promise { + const buff = await this.channel.call('readFile', [resource]); + + return buff.buffer; } - close(fd: number): Promise { - return this.channel.call('close', [fd]); - } - - async read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { - const [bytes, bytesRead]: [VSBuffer, number] = await this.channel.call('read', [fd, pos, length]); - - // copy back the data that was written into the buffer on the remote - // side. we need to do this because buffers are not referenced by - // pointer, but only by value and as such cannot be directly written - // to from the other process. - data.set(bytes.buffer.slice(0, bytesRead), offset); - - return bytesRead; - } - - write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { - return this.channel.call('write', [fd, pos, VSBuffer.wrap(data), offset, length]); + writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { + return this.channel.call('writeFile', [resource, VSBuffer.wrap(content), opts]); } delete(resource: URI, opts: FileDeleteOptions): Promise { diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 34c0934ac1..01d745119b 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -27,8 +27,7 @@ export class RemoteAuthorityResolverError extends Error { return true; } } - - return this.isTemporarilyNotAvailable(err); + return false; } public static isTemporarilyNotAvailable(err: any): boolean { diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts index 131a211cb7..d450256ecb 100644 --- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts @@ -40,10 +40,8 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS } clearResolvedAuthority(authority: string): void { - if (this._resolveAuthorityRequests[authority]) { - this._resolveAuthorityRequests[authority].reject(errors.canceled()); - delete this._resolveAuthorityRequests[authority]; - } + this._resolveAuthorityRequests[authority].reject(errors.canceled()); + delete this._resolveAuthorityRequests[authority]; } setResolvedAuthority(resolvedAuthority: ResolvedAuthority) { diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index ce42128cf1..ad89bba4be 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5500,8 +5500,8 @@ declare module 'vscode' { /** * A type that filesystem providers should use to signal errors. * - * This class has factory methods for common error-cases, like `FileNotFound` when - * a file or folder doesn't exist, use them like so: `throw vscode.FileSystemError.FileNotFound(someUri);` + * This class has factory methods for common error-cases, like `EntryNotFound` when + * a file or folder doesn't exist, use them like so: `throw vscode.FileSystemError.EntryNotFound(someUri);` */ export class FileSystemError extends Error { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 65e7223889..923f6de0e6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -16,24 +16,6 @@ declare module 'vscode' { - //#region Joh - ExecutionContext - - export enum ExtensionExecutionContext { - Local = 1, - Remote = 2 - } - - export interface ExtensionContext { - /** - * Describes the context in which this extension is executed, e.g. - * a Node.js-context on the same machine or on a remote machine - */ - executionContext: ExtensionExecutionContext; - } - - //#endregion - - //#region Joh - call hierarchy export enum CallHierarchyDirection { diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 31b0e96b65..eed35c1a81 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -228,10 +228,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { }); } - private _doCreateUntitled(resource?: URI, mode?: string, initialValue?: string): Promise { + private _doCreateUntitled(resource?: URI, modeId?: string, initialValue?: string): Promise { return this._untitledEditorService.loadOrCreate({ resource, - mode, + modeId, initialValue, useResourcePath: Boolean(resource && resource.path) }).then(model => { diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 8a4bc5d66b..c53f566596 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -295,18 +295,14 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { const codeActionsOnSave = Object.keys(setting) .filter(x => setting[x]).map(x => new CodeActionKind(x)) .sort((a, b) => { - if (CodeActionKind.SourceFixAll.contains(a)) { - if (CodeActionKind.SourceFixAll.contains(b)) { - return 0; - } - return 1; - } - if (CodeActionKind.SourceFixAll.contains(b)) { + if (a.value === CodeActionKind.SourceFixAll.value) { return -1; } + if (b.value === CodeActionKind.SourceFixAll.value) { + return 1; + } return 0; }); - if (!codeActionsOnSave.length) { return undefined; } @@ -322,8 +318,11 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { reject(localize('codeActionsOnSave.didTimeout', "Aborted codeActionsOnSave after {0}ms", timeout)); }, timeout)), this.applyOnSaveActions(model, codeActionsOnSave, tokenSource.token) - ]).finally(() => { + ]).then(() => { tokenSource.cancel(); + }, (e) => { + tokenSource.cancel(); + return Promise.reject(e); }); } diff --git a/src/vs/workbench/api/common/extHostExtensionActivator.ts b/src/vs/workbench/api/common/extHostExtensionActivator.ts index 67356e70d8..b126ac0ab9 100644 --- a/src/vs/workbench/api/common/extHostExtensionActivator.ts +++ b/src/vs/workbench/api/common/extHostExtensionActivator.ts @@ -25,7 +25,6 @@ export interface IExtensionContext { globalStoragePath: string; asAbsolutePath(relativePath: string): string; readonly logPath: string; - executionContext: number; } /** diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index cf59f0805a..b9fc9ef535 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2307,8 +2307,3 @@ export class QuickInputButtons { private constructor() { } } - -export enum ExtensionExecutionContext { - Local = 1, - Remote = 2 -} diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index ab59191f70..d75c163c3a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -182,7 +182,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews public $setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void { if (typeof handle === 'number') { - this.getWebviewElement(handle).html = value; + this.getWebviewElement(handle).contents = value; } else { const webview = this.getWebview(handle); webview.html = value; diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index c802c9d35c..b7be4d7cb2 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -800,7 +800,6 @@ export function createApiFactory( DocumentSymbol: extHostTypes.DocumentSymbol, EndOfLine: extHostTypes.EndOfLine, EventEmitter: Emitter, - ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext, CustomExecution: extHostTypes.CustomExecution, FileChangeType: extHostTypes.FileChangeType, FileSystemError: extHostTypes.FileSystemError, diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 56e16d3aeb..1d23139aa5 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -36,7 +36,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; -import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes'; +import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes'; interface ITestRunner { run(testsRoot: string, clb: (error: Error, failures?: number) => void): void; @@ -367,8 +367,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { storagePath: this._storagePath.workspaceValue(extensionDescription), globalStoragePath: this._storagePath.globalValue(extensionDescription), asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); }, - logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier), - executionContext: this._initData.remoteAuthority ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local + logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier) }); }); } @@ -629,7 +628,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { const resolver = this._resolvers[authorityPrefix]; if (!resolver) { - throw new Error(`No remote extension installed to resolve ${authorityPrefix}.`); + throw new Error(`No resolver available for ${authorityPrefix}`); } try { diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index cc2f1465f7..8fedfa57b4 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -21,7 +21,6 @@ import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; // {{SQL CARBON EDIT}} // import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; const RENDERER_NO_PROCESS_ID = -1; @@ -472,7 +471,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { .inspect(key.substr(key.lastIndexOf('.') + 1)); return this._apiInspectConfigToPlain(setting); }; - terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false, getDefaultShell(platform.platform)); + terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false); } // Get the initial cwd @@ -507,7 +506,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { // Fork the process and listen for messages this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env); - const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, terminalConfig.get('windowsEnableConpty') as boolean, this._logService); + const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, terminalConfig.get('windowsEnableConpty') as boolean); p.onProcessIdReady(pid => this._proxy.$sendProcessPid(id, pid)); p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); p.onProcessData(data => this._proxy.$sendProcessData(id, data)); diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index a6d1f5cede..af67436be7 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -19,7 +19,7 @@ import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { isWindows, isLinux } from 'vs/base/common/platform'; -import { IsMacContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacContext } from 'vs/workbench/common/contextkeys'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { InEditorZenModeContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 8a08fb6582..9d6a8cdee2 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Component } from 'vs/workbench/common/component'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IComposite, ICompositeControl } from 'vs/workbench/common/composite'; @@ -170,12 +170,12 @@ export abstract class Composite extends Component implements IComposite { } /** - * For any of the actions returned by this composite, provide an IActionViewItem in + * For any of the actions returned by this composite, provide an IActionItem in * cases where the implementor of the composite wants to override the presentation * of an action. Returns undefined to indicate that the action is not rendered through * an action item. */ - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { return undefined; } diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 4d11c2605e..92e9b8f71d 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -5,10 +5,11 @@ import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext } from 'vs/workbench/common/editor'; +import { IsMacContext, IsLinuxContext, IsWindowsContext, HasMacNativeTabsContext, IsDevelopmentContext, SupportsWorkspacesContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteAuthorityContext } from 'vs/workbench/common/contextkeys'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -18,25 +19,6 @@ import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/ import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; - -export const IsMacContext = new RawContextKey('isMac', isMacintosh); -export const IsLinuxContext = new RawContextKey('isLinux', isLinux); -export const IsWindowsContext = new RawContextKey('isWindows', isWindows); - -export const RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); - -export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); - -export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); - -export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); - -export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined); - -export const WorkspaceFolderCountContext = new RawContextKey('workspaceFolderCount', 0); - -export const RemoteFileDialogContext = new RawContextKey('remoteFileDialogVisible', false); export class WorkbenchContextKeysHandler extends Disposable { private inputFocusedContext: IContextKey; diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 03abb9d7d8..f0e18376df 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -30,7 +30,6 @@ import { addDisposableListener, EventType } from 'vs/base/browser/dom'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IRecentFile } from 'vs/platform/history/common/history'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { withNullAsUndefined } from 'vs/base/common/types'; export interface IDraggedResource { resource: URI; @@ -82,12 +81,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array { - resources.push({ - resource: URI.parse(draggedEditor.resource), - backupResource: draggedEditor.backupResource ? URI.parse(draggedEditor.backupResource) : undefined, - viewState: withNullAsUndefined(draggedEditor.viewState), - isExternal: false - }); + resources.push({ resource: URI.parse(draggedEditor.resource), backupResource: draggedEditor.backupResource ? URI.parse(draggedEditor.backupResource) : undefined, viewState: draggedEditor.viewState, isExternal: false }); }); } catch (error) { // Invalid transfer @@ -246,7 +240,7 @@ export class ResourcesDropHandler { return this.backupFileService.resolveBackupContent(droppedDirtyEditor.backupResource!).then(content => { // Set the contents of to the resource to the target - return this.backupFileService.backupResource(droppedDirtyEditor.resource, content.value.create(this.getDefaultEOL()).createSnapshot(true)); + return this.backupFileService.backupResource(droppedDirtyEditor.resource, content!.create(this.getDefaultEOL()).createSnapshot(true)); }).then(() => false, () => false /* ignore any error */); } diff --git a/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts index d80a5a925e..ef125258f3 100644 --- a/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -77,7 +77,7 @@ export class EditorDescriptor implements IEditorDescriptor { } describes(obj: unknown): boolean { - return obj instanceof BaseEditor && obj.getId() === this.id; + return obj instanceof BaseEditor && (obj).getId() === this.id; } } @@ -108,7 +108,7 @@ class EditorRegistry implements IEditorRegistry { const matchingDescriptors: EditorDescriptor[] = []; for (const editor of this.editors) { - const inputDescriptors: SyncDescriptor[] = editor[INPUT_DESCRIPTORS_PROPERTY]; + const inputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; for (const inputDescriptor of inputDescriptors) { const inputClass = inputDescriptor.ctor; diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index bd043e6d97..22d63b3a97 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -21,7 +21,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Event, Emitter } from 'vs/base/common/event'; import { ILabelService } from 'vs/platform/label/common/label'; -import { getIconClasses, detectModeId } from 'vs/editor/common/services/getIconClasses'; +import { getIconClasses, getConfiguredLangId } from 'vs/editor/common/services/getIconClasses'; import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -121,16 +121,7 @@ export class ResourceLabels extends Disposable { return; // ignore transitions in files from no mode to specific mode because this happens each time a model is created } - this._widgets.forEach(widget => widget.notifyModelModeChanged(e.model)); - })); - - // notify when model is added - this._register(this.modelService.onModelAdded(model => { - if (!model.uri) { - return; // we need the resource to compare - } - - this._widgets.forEach(widget => widget.notifyModelAdded(model)); + this._widgets.forEach(widget => widget.notifyModelModeChanged(e)); })); // notify when file decoration changes @@ -237,7 +228,7 @@ class ResourceLabelWidget extends IconLabel { private label?: IResourceLabelProps; private options?: IResourceLabelOptions; private computedIconClasses?: string[]; - private lastKnownDetectedModeId?: string; + private lastKnownConfiguredLangId?: string; private computedPathLabel?: string; private needsRedraw?: Redraw; @@ -267,21 +258,13 @@ class ResourceLabelWidget extends IconLabel { } } - notifyModelModeChanged(model: ITextModel): void { - this.handleModelEvent(model); - } - - notifyModelAdded(model: ITextModel): void { - this.handleModelEvent(model); - } - - private handleModelEvent(model: ITextModel): void { + notifyModelModeChanged(e: { model: ITextModel; oldModeId: string; }): void { if (!this.label || !this.label.resource) { return; // only update if label exists } - if (model.uri.toString() === this.label.resource.toString()) { - if (this.lastKnownDetectedModeId !== model.getModeId()) { + if (e.model.uri.toString() === this.label.resource.toString()) { + if (this.lastKnownConfiguredLangId !== e.model.getLanguageIdentifier().language) { this.render(true); // update if the language id of the model has changed from our last known state } } @@ -350,7 +333,7 @@ class ResourceLabelWidget extends IconLabel { setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void { this.setResource({ - resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }), + resource: withNullAsUndefined(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })), name: withNullAsUndefined(editor.getName()), description: withNullAsUndefined(editor.getDescription()) }, options); @@ -384,7 +367,7 @@ class ResourceLabelWidget extends IconLabel { clear(): void { this.label = undefined; this.options = undefined; - this.lastKnownDetectedModeId = undefined; + this.lastKnownConfiguredLangId = undefined; this.computedIconClasses = undefined; this.computedPathLabel = undefined; @@ -405,10 +388,10 @@ class ResourceLabelWidget extends IconLabel { } if (this.label) { - const detectedModeId = this.label.resource ? withNullAsUndefined(detectModeId(this.modelService, this.modeService, this.label.resource)) : undefined; - if (this.lastKnownDetectedModeId !== detectedModeId) { + const configuredLangId = this.label.resource ? withNullAsUndefined(getConfiguredLangId(this.modelService, this.modeService, this.label.resource)) : undefined; + if (this.lastKnownConfiguredLangId !== configuredLangId) { clearIconCache = true; - this.lastKnownDetectedModeId = detectedModeId; + this.lastKnownConfiguredLangId = configuredLangId; } } @@ -482,7 +465,7 @@ class ResourceLabelWidget extends IconLabel { this.label = undefined; this.options = undefined; - this.lastKnownDetectedModeId = undefined; + this.lastKnownConfiguredLangId = undefined; this.computedIconClasses = undefined; this.computedPathLabel = undefined; } diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index a4c0b5b4de..8c59677c0d 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -10,7 +10,7 @@ import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/brow import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; -import { pathsToEditors } from 'vs/workbench/common/editor'; +import { IUntitledResourceInput, pathsToEditors } from 'vs/workbench/common/editor'; import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; @@ -425,7 +425,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return []; // do not open any empty untitled file if we have backups to restore } - return [Object.create(null)]; // open empty untitled file + return [{}]; }); } diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 6f69614762..12873f7111 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -39,10 +39,6 @@ body { user-select: none; } -body.web { - position: fixed; /* prevent bounce effect */ -} - @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .monaco-workbench { diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/nodeless.main.ts similarity index 98% rename from src/vs/workbench/browser/web.main.ts rename to src/vs/workbench/browser/nodeless.main.ts index 547e522af5..dfc39bab1c 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/nodeless.main.ts @@ -8,7 +8,7 @@ import { domContentLoaded, addDisposableListener, EventType } from 'vs/base/brow import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILogService } from 'vs/platform/log/common/log'; import { Disposable } from 'vs/base/common/lifecycle'; -import { SimpleLogService, SimpleProductService, SimpleWorkbenchEnvironmentService } from 'vs/workbench/browser/web.simpleservices'; +import { SimpleLogService, SimpleProductService, SimpleWorkbenchEnvironmentService } from 'vs/workbench/browser/nodeless.simpleservices'; import { Workbench } from 'vs/workbench/browser/workbench'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/nodeless.simpleservices.ts similarity index 96% rename from src/vs/workbench/browser/web.simpleservices.ts rename to src/vs/workbench/browser/nodeless.simpleservices.ts index 8bbcaf6e8a..6db31aa25c 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/nodeless.simpleservices.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; -import { ITextSnapshot } from 'vs/editor/common/model'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; import { keys, ResourceMap } from 'vs/base/common/map'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -58,11 +58,11 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { Color, RGBA } from 'vs/base/common/color'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; -export const workspaceResource = URI.file((self).USER_HOME_DIR || '/').with({ +export const workspaceResource = URI.from({ scheme: Schemas.vscodeRemote, - authority: document.location.host + authority: document.location.host, + path: (self).USER_HOME_DIR || '/' }); //#region Backup File @@ -86,20 +86,20 @@ export class SimpleBackupFileService implements IBackupFileService { return Promise.resolve(undefined); } - backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + backupResource(resource: URI, content: ITextSnapshot, versionId?: number): Promise { const backupResource = this.toBackupResource(resource); this.backups.set(backupResource.toString(), content); return Promise.resolve(); } - resolveBackupContent(backupResource: URI): Promise> { + resolveBackupContent(backupResource: URI): Promise { const snapshot = this.backups.get(backupResource.toString()); if (snapshot) { - return Promise.resolve({ value: createTextBufferFactoryFromSnapshot(snapshot) }); + return Promise.resolve(createTextBufferFactoryFromSnapshot(snapshot)); } - return Promise.reject('Unexpected backup resource to resolve'); + return Promise.resolve(undefined); } getWorkspaceFileBackups(): Promise { @@ -234,14 +234,14 @@ export class SimpleWorkbenchEnvironmentService implements IWorkbenchEnvironmentS args = { _: [] }; execPath: string; cliPath: string; - appRoot: string = '/web/'; + appRoot: string = '/nodeless/'; userHome: string; userDataPath: string; appNameLong: string; appQuality?: string; - appSettingsHome: string = '/web/settings'; - appSettingsPath: string = '/web/settings/settings.json'; - appKeybindingsPath: string = '/web/settings/keybindings.json'; + appSettingsHome: string = '/nodeless/settings'; + appSettingsPath: string = '/nodeless/settings/settings.json'; + appKeybindingsPath: string = '/nodeless/settings/keybindings.json'; machineSettingsHome: string; machineSettingsPath: string; settingsSearchBuildId?: number; @@ -264,7 +264,7 @@ export class SimpleWorkbenchEnvironmentService implements IWorkbenchEnvironmentS wait: boolean; status: boolean; log?: string; - logsPath: string = '/web/logs'; + logsPath: string = '/nodeless/logs'; verbose: boolean; skipGettingStarted: boolean; skipReleaseNotes: boolean; @@ -702,8 +702,7 @@ export class SimpleSearchService implements ISearchService { constructor( @IModelService private modelService: IModelService, @IEditorService private editorService: IEditorService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService, - @IFileService private fileService: IFileService + @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { } @@ -733,8 +732,8 @@ export class SimpleSearchService implements ISearchService { return Disposable.None; } - private getLocalResults(query: ITextQuery): ResourceMap { - const localResults = new ResourceMap(); + private getLocalResults(query: ITextQuery): ResourceMap { + const localResults = new ResourceMap(); if (query.type === QueryType.Text) { const models = this.modelService.getModels(); @@ -755,8 +754,10 @@ export class SimpleSearchService implements ISearchService { } } - // Block walkthrough, webview, etc. - else if (!this.fileService.canHandleResource(resource)) { + // Don't support other resource schemes than files for now + // why is that? we should search for resources from other + // schemes + else if (resource.scheme !== Schemas.file) { return; } @@ -765,7 +766,8 @@ export class SimpleSearchService implements ISearchService { } // Use editor API to find matches - const matches = model.findMatches(query.contentPattern.pattern, false, !!query.contentPattern.isRegExp, !!query.contentPattern.isCaseSensitive, query.contentPattern.isWordMatch ? query.contentPattern.wordSeparators! : null, false, query.maxResults); + // @ts-ignore + const matches = model.findMatches(query.contentPattern.pattern, false, query.contentPattern.isRegExp, query.contentPattern.isCaseSensitive, query.contentPattern.isWordMatch ? query.contentPattern.wordSeparators : null, false, query.maxResults); if (matches.length) { const fileMatch = new FileMatch(resource); localResults.set(resource, fileMatch); @@ -773,6 +775,7 @@ export class SimpleSearchService implements ISearchService { const textSearchResults = editorMatchesToTextSearchResults(matches, model, query.previewOptions); fileMatch.results = addContextToEditorMatches(textSearchResults, model, query); } else { + // @ts-ignore localResults.set(resource, null); } }); @@ -782,6 +785,13 @@ export class SimpleSearchService implements ISearchService { } private matches(resource: URI, query: ITextQuery): boolean { + // includes + if (query.includePattern) { + if (resource.scheme !== Schemas.file) { + return false; // if we match on file patterns, we have to ignore non file resources + } + } + return pathIncludedInQuery(query, resource.fsPath); } } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 1a7709f21d..40bf14f901 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -18,7 +18,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; +import { ActivityAction, ActivityActionItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { IActivity, IGlobalActivity } from 'vs/workbench/common/activity'; @@ -110,7 +110,7 @@ export class GlobalActivityAction extends ActivityAction { } } -export class GlobalActivityActionViewItem extends ActivityActionViewItem { +export class GlobalActivityActionItem extends ActivityActionItem { constructor( action: GlobalActivityAction, diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index cc98b6a610..5f3b186cb4 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -10,7 +10,7 @@ import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/acti import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity'; import { Registry } from 'vs/platform/registry/common/platform'; import { Part } from 'vs/workbench/browser/part'; -import { GlobalActivityActionViewItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewletActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; +import { GlobalActivityActionItem, GlobalActivityAction, ViewletActivityAction, ToggleViewletAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewletActivityAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService'; @@ -87,7 +87,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } - this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => ({ id: v.id, name: undefined, visible: v.visible, order: v.order, pinned: v.pinned })), { + this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => ({ id: v.id, name: undefined, visible: v.visible, order: v.order, pinned: v.pinned })), { icon: true, orientation: ActionsOrientation.VERTICAL, openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), @@ -218,7 +218,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } private getActivitybarItemColors(theme: ITheme): ICompositeBarColors { - return { + return { activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), @@ -236,7 +236,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { .map(a => new GlobalActivityAction(a)); this.globalActionBar = this._register(new ActionBar(container, { - actionViewItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionViewItem, a, (theme: ITheme) => this.getActivitybarItemColors(theme)), + actionItemProvider: a => this.instantiationService.createInstance(GlobalActivityActionItem, a, (theme: ITheme) => this.getActivitybarItemColors(theme)), orientation: ActionsOrientation.VERTICAL, ariaLabel: nls.localize('globalActions', "Global Actions"), animated: false @@ -380,7 +380,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Layout composite bar let availableHeight = contentAreaSize.height; if (this.globalActionBar) { - availableHeight -= (this.globalActionBar.viewItems.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing + availableHeight -= (this.globalActionBar.items.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing } this.compositeBar.layout(new Dimension(width, availableHeight)); } @@ -446,9 +446,9 @@ export class ActivitybarPart extends Part implements IActivityBarService { } private getCachedViewlets(): ICachedViewlet[] { - const storedStates: Array = JSON.parse(this.cachedViewletsValue); - const cachedViewlets = storedStates.map(c => { - const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, iconUrl: undefined, views: undefined } : c; + const storedStates = >JSON.parse(this.cachedViewletsValue); + const cachedViewlets = storedStates.map(c => { + const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, iconUrl: undefined, views: undefined } : c; serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible; return serialized; }); @@ -466,7 +466,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private loadOldCachedViewlets(): ICachedViewlet[] { const previousState = this.storageService.get('workbench.activity.placeholderViewlets', StorageScope.GLOBAL, '[]'); - const result: ICachedViewlet[] = JSON.parse(previousState); + const result = (JSON.parse(previousState)); this.storageService.remove('workbench.activity.placeholderViewlets', StorageScope.GLOBAL); return result; diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index aab53093e4..81131222fd 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -11,7 +11,7 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CompositeActionViewItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionViewItem, ActivityAction, ICompositeBar, ICompositeBarColors, DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions'; +import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors, DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions'; import { Dimension, $, addDisposableListener, EventType, EventHelper } from 'vs/base/browser/dom'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -50,7 +50,7 @@ export class CompositeBar extends Widget implements ICompositeBar { private compositeSwitcherBar: ActionBar; private compositeOverflowAction: CompositeOverflowActivityAction | null; - private compositeOverflowActionViewItem: CompositeOverflowActivityActionViewItem | undefined; + private compositeOverflowActionItem: CompositeOverflowActivityActionItem | undefined; private model: CompositeBarModel; private visibleComposites: string[]; @@ -93,12 +93,12 @@ export class CompositeBar extends Widget implements ICompositeBar { create(parent: HTMLElement): HTMLElement { const actionBarDiv = parent.appendChild($('.composite-bar')); this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { - actionViewItemProvider: (action: Action) => { + actionItemProvider: (action: Action) => { if (action instanceof CompositeOverflowActivityAction) { - return this.compositeOverflowActionViewItem; + return this.compositeOverflowActionItem; } const item = this.model.findItem(action.id); - return item && this.instantiationService.createInstance(CompositeActionViewItem, action, item.pinnedAction, () => this.getContextMenuActions(), this.options.colors, this.options.icon, this); + return item && this.instantiationService.createInstance(CompositeActionItem, action, item.pinnedAction, () => this.getContextMenuActions(), this.options.colors, this.options.icon, this); }, orientation: this.options.orientation, ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"), @@ -278,13 +278,13 @@ export class CompositeBar extends Widget implements ICompositeBar { } else { if (this.dimension && this.dimension.height !== 0 && this.dimension.width !== 0) { // Compute sizes only if visible. Otherwise the size measurment would be computed wrongly. - const currentItemsLength = this.compositeSwitcherBar.viewItems.length; + const currentItemsLength = this.compositeSwitcherBar.items.length; this.compositeSwitcherBar.push(items.map(composite => composite.activityAction)); items.map((composite, index) => this.compositeSizeInBar.set(composite.id, this.options.orientation === ActionsOrientation.VERTICAL ? this.compositeSwitcherBar.getHeight(currentItemsLength + index) : this.compositeSwitcherBar.getWidth(currentItemsLength + index) )); - items.forEach(() => this.compositeSwitcherBar.pull(this.compositeSwitcherBar.viewItems.length - 1)); + items.forEach(() => this.compositeSwitcherBar.pull(this.compositeSwitcherBar.items.length - 1)); } } } @@ -343,10 +343,10 @@ export class CompositeBar extends Widget implements ICompositeBar { this.compositeOverflowAction.dispose(); this.compositeOverflowAction = null; - if (this.compositeOverflowActionViewItem) { - this.compositeOverflowActionViewItem.dispose(); + if (this.compositeOverflowActionItem) { + this.compositeOverflowActionItem.dispose(); } - this.compositeOverflowActionViewItem = undefined; + this.compositeOverflowActionItem = undefined; } // Pull out composites that overflow or got hidden @@ -357,9 +357,9 @@ export class CompositeBar extends Widget implements ICompositeBar { } }); compositesToRemove.reverse().forEach(index => { - const actionViewItem = this.compositeSwitcherBar.viewItems[index]; + const actionItem = this.compositeSwitcherBar.items[index]; this.compositeSwitcherBar.pull(index); - actionViewItem.dispose(); + actionItem.dispose(); this.visibleComposites.splice(index, 1); }); @@ -368,9 +368,9 @@ export class CompositeBar extends Widget implements ICompositeBar { const currentIndex = this.visibleComposites.indexOf(compositeId); if (newIndex !== currentIndex) { if (currentIndex !== -1) { - const actionViewItem = this.compositeSwitcherBar.viewItems[currentIndex]; + const actionItem = this.compositeSwitcherBar.items[currentIndex]; this.compositeSwitcherBar.pull(currentIndex); - actionViewItem.dispose(); + actionItem.dispose(); this.visibleComposites.splice(currentIndex, 1); } @@ -382,12 +382,12 @@ export class CompositeBar extends Widget implements ICompositeBar { // Add overflow action as needed if ((visibleCompositesChange && overflows) || this.compositeSwitcherBar.length() === 0) { this.compositeOverflowAction = this.instantiationService.createInstance(CompositeOverflowActivityAction, () => { - if (this.compositeOverflowActionViewItem) { - this.compositeOverflowActionViewItem.showMenu(); + if (this.compositeOverflowActionItem) { + this.compositeOverflowActionItem.showMenu(); } }); - this.compositeOverflowActionViewItem = this.instantiationService.createInstance( - CompositeOverflowActivityActionViewItem, + this.compositeOverflowActionItem = this.instantiationService.createInstance( + CompositeOverflowActivityActionItem, this.compositeOverflowAction, () => this.getOverflowingComposites(), () => this.model.activeItem ? this.model.activeItem.id : undefined, diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index e77d9557f9..ee93c8cfb6 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; -import { BaseActionViewItem, IBaseActionViewItemOptions, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem, IBaseActionItemOptions, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { dispose, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -118,16 +118,16 @@ export interface ICompositeBarColors { dragAndDropBackground?: Color; } -export interface IActivityActionViewItemOptions extends IBaseActionViewItemOptions { +export interface IActivityActionItemOptions extends IBaseActionItemOptions { icon?: boolean; colors: (theme: ITheme) => ICompositeBarColors; } -export class ActivityActionViewItem extends BaseActionViewItem { +export class ActivityActionItem extends BaseActionItem { protected container: HTMLElement; protected label: HTMLElement; protected badge: HTMLElement; - protected options: IActivityActionViewItemOptions; + protected options: IActivityActionItemOptions; private badgeContent: HTMLElement; private badgeDisposable: IDisposable = Disposable.None; @@ -135,7 +135,7 @@ export class ActivityActionViewItem extends BaseActionViewItem { constructor( action: ActivityAction, - options: IActivityActionViewItemOptions, + options: IActivityActionItemOptions, @IThemeService protected themeService: IThemeService ) { super(null, action, options); @@ -347,7 +347,7 @@ export class CompositeOverflowActivityAction extends ActivityAction { } } -export class CompositeOverflowActivityActionViewItem extends ActivityActionViewItem { +export class CompositeOverflowActivityActionItem extends ActivityActionItem { private actions: Action[]; constructor( @@ -428,7 +428,7 @@ export class DraggedCompositeIdentifier { } } -export class CompositeActionViewItem extends ActivityActionViewItem { +export class CompositeActionItem extends ActivityActionItem { private static manageExtensionAction: ManageExtensionAction; @@ -451,8 +451,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem { this.compositeTransfer = LocalSelectionTransfer.getInstance(); - if (!CompositeActionViewItem.manageExtensionAction) { - CompositeActionViewItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); + if (!CompositeActionItem.manageExtensionAction) { + CompositeActionItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction); } this._register(compositeActivityAction.onDidChangeActivity(() => { this.compositeActivity = null; this.updateActivity(); }, this)); @@ -569,7 +569,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { const actions: Action[] = [this.toggleCompositePinnedAction]; if ((this.compositeActivityAction.activity).extensionId) { actions.push(new Separator()); - actions.push(CompositeActionViewItem.manageExtensionAction); + actions.push(CompositeActionItem.manageExtensionAction); } const isPinned = this.compositeBar.isPinned(this.activity.id); diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 6bc5648cdc..5e6a95a025 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -11,7 +11,7 @@ import * as strings from 'vs/base/common/strings'; import { Emitter } from 'vs/base/common/event'; import * as errors from 'vs/base/common/errors'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IActionViewItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { prepareActions } from 'vs/workbench/browser/actions'; import { IAction } from 'vs/base/common/actions'; @@ -399,7 +399,7 @@ export abstract class CompositePart extends Part { // Toolbar this.toolBar = this._register(new ToolBar(titleActionsContainer, this.contextMenuService, { - actionViewItemProvider: action => this.actionViewItemProvider(action), + actionItemProvider: action => this.actionItemProvider(action), orientation: ActionsOrientation.HORIZONTAL, getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment() @@ -432,11 +432,11 @@ export abstract class CompositePart extends Part { this.titleLabel.updateStyles(); } - protected actionViewItemProvider(action: IAction): IActionViewItem | undefined { + protected actionItemProvider(action: IAction): IActionItem | undefined { // Check Active Composite if (this.activeComposite) { - return this.activeComposite.getActionViewItem(action); + return this.activeComposite.getActionItem(action); } return undefined; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index d7ce23e96a..e9ecda5eae 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -70,7 +70,7 @@ class Item extends BreadcrumbsItem { return false; } if (this.element instanceof FileElement && other.element instanceof FileElement) { - return isEqual(this.element.uri, other.element.uri, false); + return isEqual(this.element.uri, other.element.uri); } if (this.element instanceof TreeElement && other.element instanceof TreeElement) { return this.element.id === other.element.id; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index 4b41436b2b..55decba633 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -388,14 +388,21 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */); this._disposables.push(labels); - return this._instantiationService.createInstance(WorkbenchAsyncDataTree, container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), { - filterOnType: true, - multipleSelectionSupport: false, - sorter: new FileSorter(), - filter: this._instantiationService.createInstance(FileFilter), - identityProvider: new FileIdentityProvider(), - keyboardNavigationLabelProvider: new FileNavigationLabelProvider() - }) as WorkbenchAsyncDataTree; + return this._instantiationService.createInstance( + WorkbenchAsyncDataTree, + container, + new FileVirtualDelegate(), + [this._instantiationService.createInstance(FileRenderer, labels)], + this._instantiationService.createInstance(FileDataSource), + { + filterOnType: true, + multipleSelectionSupport: false, + sorter: new FileSorter(), + filter: this._instantiationService.createInstance(FileFilter), + identityProvider: new FileIdentityProvider(), + keyboardNavigationLabelProvider: new FileNavigationLabelProvider() + } + ) as WorkbenchAsyncDataTree; } _setInput(element: BreadcrumbElement): Promise { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index fd4961f880..ca335f65e1 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -104,7 +104,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( interface ISerializedUntitledEditorInput { resource: string; resourceJSON: object; - modeId: string | undefined; + modeId: string | null; encoding: string; } @@ -136,7 +136,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory { const serialized: ISerializedUntitledEditorInput = { resource: resource.toString(), // Keep for backwards compatibility resourceJSON: resource.toJSON(), - modeId: untitledEditorInput.getMode(), + modeId: untitledEditorInput.getModeId(), encoding: untitledEditorInput.getEncoding() }; @@ -147,10 +147,10 @@ class UntitledEditorInputFactory implements IEditorInputFactory { return instantiationService.invokeFunction(accessor => { const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput); const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource); - const mode = deserialized.modeId; + const language = deserialized.modeId; const encoding = deserialized.encoding; - return accessor.get(IEditorService).createInput({ resource, mode, encoding, forceUntitled: true }) as UntitledEditorInput; + return accessor.get(IEditorService).createInput({ resource, language, encoding, forceUntitled: true }) as UntitledEditorInput; }); } } diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 8a48eea3e9..09ea926a4f 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -449,7 +449,7 @@ export function toEditorQuickOpenEntry(element: any): IEditorQuickOpenEntry | nu // QuickOpenEntryGroup if (element instanceof QuickOpenEntryGroup) { - const group = element; + const group = element; if (group.getEntry()) { element = group.getEntry(); } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 81b34791d1..9fa7efad88 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -40,7 +40,7 @@ import { CLOSE_EDITOR_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor import { NoTabsTitleControl } from 'vs/workbench/browser/parts/editor/noTabsTitleControl'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; // {{SQL CARBON EDIT}} import { ICommandService } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 5b6f5905f7..a718c15fcd 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -18,7 +18,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { EditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { withNullAsUndefined } from 'vs/base/common/types'; export class EditorPickerEntry extends QuickOpenEntryGroup { @@ -33,13 +32,13 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { getLabelOptions(): IIconLabelValueOptions { return { - extraClasses: getIconClasses(this.modelService, this.modeService, this.getResource()), + extraClasses: getIconClasses(this.modelService, this.modeService, this.getResource() || undefined), italic: !this._group.isPinned(this.editor) }; } getLabel() { - return withNullAsUndefined(this.editor.getName()); + return this.editor.getName(); } getIcon(): string { @@ -59,7 +58,7 @@ export class EditorPickerEntry extends QuickOpenEntryGroup { } getDescription() { - return withNullAsUndefined(this.editor.getDescription()); + return this.editor.getDescription(); } run(mode: Mode, context: IEntryRunContext): boolean { diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 39dbaacb3b..2d90c43fd1 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -14,11 +14,11 @@ import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { Action } from 'vs/base/common/actions'; import { Language } from 'vs/base/common/platform'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; -import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput, SideBySideEditor, IModeSupport } from 'vs/workbench/common/editor'; +import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor'; import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IEditorAction } from 'vs/editor/common/editorCommon'; -import { EndOfLineSequence } from 'vs/editor/common/model'; +import { EndOfLineSequence, ITextModel } from 'vs/editor/common/model'; import { IModelLanguageChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { TrimTrailingWhitespaceAction } from 'vs/editor/contrib/linesOperations/linesOperations'; import { IndentUsingSpaces, IndentUsingTabs, DetectIndentation, IndentationToSpacesAction, IndentationToTabsAction } from 'vs/editor/contrib/indentation/indentation'; @@ -62,15 +62,7 @@ class SideBySideEditorEncodingSupport implements IEncodingSupport { } setEncoding(encoding: string, mode: EncodingMode): void { - [this.master, this.details].forEach(editor => editor.setEncoding(encoding, mode)); - } -} - -class SideBySideEditorModeSupport implements IModeSupport { - constructor(private master: IModeSupport, private details: IModeSupport) { } - - setMode(mode: string): void { - [this.master, this.details].forEach(editor => editor.setMode(mode)); + [this.master, this.details].forEach(s => s.setEncoding(encoding, mode)); } } @@ -94,7 +86,7 @@ function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport | nu } // File or Resource Editor - const encodingSupport = input as IFileEditorInput; + let encodingSupport = input as IFileEditorInput; if (areFunctions(encodingSupport.setEncoding, encodingSupport.getEncoding)) { return encodingSupport; } @@ -103,41 +95,14 @@ function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport | nu return null; } -function toEditorWithModeSupport(input: IEditorInput): IModeSupport | null { - - // Untitled Editor - if (input instanceof UntitledEditorInput) { - return input; - } - - // Side by Side (diff) Editor - if (input instanceof SideBySideEditorInput) { - const masterModeSupport = toEditorWithModeSupport(input.master); - const detailsModeSupport = toEditorWithModeSupport(input.details); - - if (masterModeSupport && detailsModeSupport) { - return new SideBySideEditorModeSupport(masterModeSupport, detailsModeSupport); - } - - return masterModeSupport; - } - - // File or Resource Editor - const modeSupport = input as IFileEditorInput; - if (typeof modeSupport.setMode === 'function') { - return modeSupport; - } - - // Unsupported for any other editor - return null; -} - interface IEditorSelectionStatus { selections?: Selection[]; charactersSelected?: number; } class StateChange { + _stateChangeBrand: void; + indentation: boolean = false; selectionStatus: boolean = false; mode: boolean = false; @@ -158,7 +123,7 @@ class StateChange { this.metadata = this.metadata || other.metadata; } - hasChanges(): boolean { + public hasChanges(): boolean { return this.indentation || this.selectionStatus || this.mode @@ -217,49 +182,42 @@ class State { change.selectionStatus = true; } } - if ('indentation' in update) { if (this._indentation !== update.indentation) { this._indentation = update.indentation; change.indentation = true; } } - if ('mode' in update) { if (this._mode !== update.mode) { this._mode = update.mode; change.mode = true; } } - if ('encoding' in update) { if (this._encoding !== update.encoding) { this._encoding = update.encoding; change.encoding = true; } } - if ('EOL' in update) { if (this._EOL !== update.EOL) { this._EOL = update.EOL; change.EOL = true; } } - if ('tabFocusMode' in update) { if (this._tabFocusMode !== update.tabFocusMode) { this._tabFocusMode = update.tabFocusMode; change.tabFocusMode = true; } } - if ('screenReaderMode' in update) { if (this._screenReaderMode !== update.screenReaderMode) { this._screenReaderMode = update.screenReaderMode; change.screenReaderMode = true; } } - if ('metadata' in update) { if (this._metadata !== update.metadata) { this._metadata = update.metadata; @@ -281,6 +239,7 @@ const nlsTabFocusMode = nls.localize('tabFocusModeEnabled', "Tab Moves Focus"); const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Optimized"); const nlsScreenReaderDetectedTitle = nls.localize('screenReaderDetectedExtra', "If you are not using a Screen Reader, please change the setting `editor.accessibilitySupport` to \"off\"."); + class StatusBarItem { private _showing = true; @@ -292,15 +251,15 @@ class StatusBarItem { this.element.title = title; } - set textContent(value: string) { + public set textContent(value: string) { this.element.textContent = value; } - set onclick(value: () => void) { + public set onclick(value: () => void) { this.element.onclick = value; } - setVisible(shouldShow: boolean): void { + public setVisible(shouldShow: boolean): void { if (shouldShow !== this._showing) { this._showing = shouldShow; this.element.style.display = shouldShow ? '' : 'none'; @@ -308,6 +267,7 @@ class StatusBarItem { } } + export class EditorStatus implements IStatusbarItem { private state: State; private element: HTMLElement; @@ -704,7 +664,7 @@ export class EditorStatus implements IStatusbarItem { this.updateState(update); } - private promptedScreenReader: boolean = false; + private _promptedScreenReader: boolean = false; private onScreenReaderModeChange(editorWidget: ICodeEditor | undefined): void { let screenReaderMode = false; @@ -716,8 +676,8 @@ export class EditorStatus implements IStatusbarItem { const screenReaderConfiguration = this.configurationService.getValue('editor').accessibilitySupport; if (screenReaderConfiguration === 'auto') { // show explanation - if (!this.promptedScreenReader) { - this.promptedScreenReader = true; + if (!this._promptedScreenReader) { + this._promptedScreenReader = true; setTimeout(() => { this.onScreenReaderModeClick(); }, 100); @@ -814,7 +774,7 @@ export class EditorStatus implements IStatusbarItem { if (activeControl) { const activeResource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER }); if (activeResource && activeResource.toString() === resource.toString()) { - return this.onEncodingChange(activeControl); // only update if the encoding changed for the active resource + return this.onEncodingChange(activeControl); // only update if the encoding changed for the active resource } } } @@ -927,7 +887,7 @@ export class ChangeModeAction extends Action { } } - return { + return { label: lang, iconClasses: getIconClasses(this.modelService, this.modeService, fakeResource), description @@ -990,35 +950,50 @@ export class ChangeModeAction extends Action { } // Change mode for active editor - const activeEditor = this.editorService.activeControl; // {{SQL CARBON EDIT}} @anthonydresser change to activeControl from active editor - if (activeEditor) { - const modeSupport = toEditorWithModeSupport(activeEditor.input); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly - if (modeSupport) { - - // Find mode - let languageSelection: ILanguageSelection | undefined; - if (pick === autoDetectMode) { - if (textModel) { - const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER }); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly - if (resource) { - languageSelection = this.modeService.createByFilepathOrFirstLine(resource.fsPath, textModel.getLineContent(1)); - } - } - } else { - languageSelection = this.modeService.createByLanguageName(pick.label); + // {{SQL CARBON EDIT}} - Get activeControl instead of activeEditor @todo anthonydresser 4/12/19 investigate + const activeEditor = this.editorService.activeControl; + const activeTextEditorWidget = this.editorService.activeTextEditorWidget; + const models: ITextModel[] = []; + if (isCodeEditor(activeTextEditorWidget)) { + const codeEditorModel = activeTextEditorWidget.getModel(); + if (codeEditorModel) { + models.push(codeEditorModel); + } + } else if (isDiffEditor(activeTextEditorWidget)) { + const diffEditorModel = activeTextEditorWidget.getModel(); + if (diffEditorModel) { + if (diffEditorModel.original) { + models.push(diffEditorModel.original); } - - // {{SQL CARBON EDIT}} @anthonydresser preform a check before we actuall set the mode - // Change mode - if (typeof languageSelection !== 'undefined') { - QueryEditorService.sqlLanguageModeCheck(textModel, languageSelection, activeEditor).then(newTextModel => { - if (newTextModel) { - modeSupport.setMode(languageSelection.languageIdentifier.language); - } - }); + if (diffEditorModel.modified) { + models.push(diffEditorModel.modified); } } } + + // Find mode + let languageSelection: ILanguageSelection | undefined; + if (pick === autoDetectMode) { + if (textModel) { + // {{SQL CARBON EDIT}} - use activeEditor.input instead of activeEditor + const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER }); + if (resource) { + languageSelection = this.modeService.createByFilepathOrFirstLine(resource.fsPath, textModel.getLineContent(1)); + } + } + } else { + languageSelection = this.modeService.createByLanguageName(pick.label); + } + + // {{SQL CARBON EDIT}} + // Change mode + models.forEach(textModel => { + QueryEditorService.sqlLanguageModeCheck(textModel, languageSelection, activeEditor).then((newTextModel) => { + if (newTextModel) { + this.modelService.setMode(newTextModel, languageSelection); + } + }); + }); }); } @@ -1029,9 +1004,9 @@ export class ChangeModeAction extends Action { const languages = this.modeService.getRegisteredLanguageNames(); const picks: IQuickPickItem[] = languages.sort().map((lang, index) => { - const id = withNullAsUndefined(this.modeService.getModeIdForLanguageName(lang.toLowerCase())); + const id = this.modeService.getModeIdForLanguageName(lang.toLowerCase()); - return { + return { id, label: lang, description: (id === currentAssociation) ? nls.localize('currentAssociation', "Current Association") : undefined @@ -1041,7 +1016,7 @@ export class ChangeModeAction extends Action { setTimeout(() => { this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || base) }).then(language => { if (language) { - const fileAssociationsConfig = this.configurationService.inspect<{}>(FILES_ASSOCIATIONS_CONFIG); + const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG); let associationKey: string; if (extension && base[0] !== '.') { @@ -1192,7 +1167,6 @@ export class ChangeEncodingAction extends Action { if (!activeControl) { return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); } - const encodingSupport: IEncodingSupport | null = toEditorWithEncodingSupport(activeControl.input); if (!encodingSupport) { return this.quickInputService.pick([{ label: nls.localize('noFileEditor', "No file active at this time") }]); @@ -1283,12 +1257,10 @@ export class ChangeEncodingAction extends Action { if (!encoding) { return; } - const activeControl = this.editorService.activeControl; if (!activeControl) { return; } - const encodingSupport = toEditorWithEncodingSupport(activeControl.input); if (typeof encoding.id !== 'undefined' && encodingSupport && encodingSupport.getEncoding() !== encoding.id) { encodingSupport.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode); // Set new encoding diff --git a/src/vs/workbench/browser/parts/editor/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts index 31b92e92f0..a022d952e2 100644 --- a/src/vs/workbench/browser/parts/editor/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -370,7 +370,7 @@ class InlineImageView { dispose: () => combinedDisposable(disposables).dispose() }; - const cacheKey = `${descriptor.resource.toString()}:${descriptor.etag}`; + const cacheKey = descriptor.resource.toString(); let ctrlPressed = false; let altPressed = false; @@ -501,8 +501,8 @@ class InlineImageView { return; } - const isScrollWheelKeyPressed = platform.isMacintosh ? altPressed : ctrlPressed; - if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl + const isScrollWhellKeyPressed = platform.isMacintosh ? altPressed : ctrlPressed; + if (!isScrollWhellKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl return; } @@ -513,8 +513,12 @@ class InlineImageView { firstZoom(); } - let delta = e.deltaY > 0 ? 1 : -1; + let delta = e.deltaY < 0 ? 1 : -1; + // Pinching should increase the scale + if (e.ctrlKey && !isScrollWhellKeyPressed) { + delta *= -1; + } updateScale(scale as number * (1 - delta * InlineImageView.SCALE_PINCH_FACTOR)); })); diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 8c1006415d..e85056a8d8 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -93,10 +93,10 @@ export class SideBySideEditor extends BaseEditor { this.updateStyles(); } - setInput(newInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise { - const oldInput = this.input as SideBySideEditorInput; + setInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise { + const oldInput = this.input; return super.setInput(newInput, options, token) - .then(() => this.updateInput(oldInput, newInput as SideBySideEditorInput, options, token)); + .then(() => this.updateInput(oldInput, newInput, options, token)); } setOptions(options: EditorOptions): void { @@ -177,8 +177,8 @@ export class SideBySideEditor extends BaseEditor { } private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise { - const detailsEditor = this.doCreateEditor(newInput.details, this.detailsEditorContainer); - const masterEditor = this.doCreateEditor(newInput.master, this.masterEditorContainer); + const detailsEditor = this.doCreateEditor(newInput.details, this.detailsEditorContainer); + const masterEditor = this.doCreateEditor(newInput.master, this.masterEditorContainer); return this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options, token); } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 1cc53647f0..55f67b8cc8 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -6,7 +6,7 @@ import { applyDragImage } from 'vs/base/browser/dnd'; import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IAction, IRunEvent } from 'vs/base/common/actions'; import * as arrays from 'vs/base/common/arrays'; @@ -15,7 +15,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./media/titlecontrol'; import { getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { localize } from 'vs/nls'; -import { createActionViewItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { createActionItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ExecuteCommandAction, IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -39,7 +39,7 @@ import { Themable } from 'vs/workbench/common/theme'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IFileService } from 'vs/platform/files/common/files'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; export interface IToolbarActions { @@ -129,7 +129,7 @@ export abstract class TitleControl extends Themable { const context: IEditorCommandsContext = { groupId: this.group.id }; this.editorActionsToolbar = this._register(new ToolBar(container, this.contextMenuService, { - actionViewItemProvider: action => this.actionViewItemProvider(action), + actionItemProvider: action => this.actionItemProvider(action), orientation: ActionsOrientation.HORIZONTAL, ariaLabel: localize('araLabelEditorActions', "Editor actions"), getKeyBinding: action => this.getKeybinding(action), @@ -159,21 +159,21 @@ export abstract class TitleControl extends Themable { })); } - private actionViewItemProvider(action: IAction): IActionViewItem | undefined { + private actionItemProvider(action: IAction): IActionItem | undefined { const activeControl = this.group.activeControl; // Check Active Editor - let actionViewItem: IActionViewItem | undefined = undefined; + let actionItem: IActionItem | undefined = undefined; if (activeControl instanceof BaseEditor) { - actionViewItem = activeControl.getActionViewItem(action); + actionItem = activeControl.getActionItem(action); } // Check extensions - if (!actionViewItem) { - actionViewItem = createActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + if (!actionItem) { + actionItem = createActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } - return actionViewItem; + return actionItem; } protected updateEditorActionsToolbar(): void { @@ -222,7 +222,7 @@ export abstract class TitleControl extends Themable { this.editorToolBarMenuDisposables = dispose(this.editorToolBarMenuDisposables); // Update the resource context - this.resourceContext.set(this.group.activeEditor ? withUndefinedAsNull(toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER })) : null); + this.resourceContext.set(this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null); // Editor actions require the editor control to be there, so we retrieve it via service const activeControl = this.group.activeControl; @@ -289,7 +289,7 @@ export abstract class TitleControl extends Themable { // Update the resource context const currentContext = this.resourceContext.get(); - this.resourceContext.set(withUndefinedAsNull(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }))); + this.resourceContext.set(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })); // Find target anchor let anchor: HTMLElement | { x: number, y: number } = node; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts index 4cd89dfe30..c3c5d81248 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts @@ -16,7 +16,7 @@ import { IAction, IActionRunner } from 'vs/base/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown'; +import { DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown'; import { INotificationViewItem, NotificationViewItem, NotificationViewItemLabelKind, INotificationMessage, ChoiceAction } from 'vs/workbench/common/notifications'; import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -219,9 +219,9 @@ export class NotificationRenderer implements IListRenderer { + actionItemProvider: action => { if (action && action instanceof ConfigureNotificationAction) { - const item = new DropdownMenuActionViewItem(action, action.configurationActions, this.contextMenuService, undefined, this.actionRunner, undefined, action.class); + const item = new DropdownMenuActionItem(action, action.configurationActions, this.contextMenuService, undefined, this.actionRunner, undefined, action.class); data.toDispose.push(item); return item; diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 06803503dc..612eca7ad0 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -394,9 +394,9 @@ export class PanelPart extends CompositePart implements IPanelService { private getCachedPanels(): ICachedPanel[] { const registeredPanels = this.getPanels(); - const storedStates: Array = JSON.parse(this.cachedPanelsValue); - const cachedPanels = storedStates.map(c => { - const serialized: ICachedPanel = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true } : c; + const storedStates = >JSON.parse(this.cachedPanelsValue); + const cachedPanels = storedStates.map(c => { + const serialized: ICachedPanel = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true } : c; const registered = registeredPanels.some(p => p.id === serialized.id); serialized.visible = registered ? isUndefinedOrNull(serialized.visible) ? true : serialized.visible : false; return serialized; diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.css b/src/vs/workbench/browser/parts/quickinput/quickInput.css index 8eccef05cd..cf3f5cffa1 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.css +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.css @@ -119,7 +119,6 @@ .quick-input-list { line-height: 22px; - margin-top: 6px; } .quick-input-list .monaco-list { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index fb53949b52..879d54d8f1 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -33,7 +33,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ICommandAndKeybindingRule, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { inQuickOpenContext, InQuickOpenContextKey } from 'vs/workbench/browser/parts/quickopen/quickopen'; -import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { URI } from 'vs/base/common/uri'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -1442,11 +1442,11 @@ export class QuickInputService extends Component implements IQuickInputService { private setEnabled(enabled: boolean) { if (enabled !== this.enabled) { this.enabled = enabled; - for (const item of this.ui.leftActionBar.viewItems) { - (item as ActionViewItem).getAction().enabled = enabled; + for (const item of this.ui.leftActionBar.items) { + (item as ActionItem).getAction().enabled = enabled; } - for (const item of this.ui.rightActionBar.viewItems) { - (item as ActionViewItem).getAction().enabled = enabled; + for (const item of this.ui.rightActionBar.items) { + (item as ActionItem).getAction().enabled = enabled; } this.ui.checkAll.disabled = !enabled; // this.ui.inputBox.enabled = enabled; Avoid loosing focus. diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index a026ac0775..7da7903fab 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -710,7 +710,7 @@ class EditorHistoryItemAccessorClass extends QuickOpenItemAccessorClass { } getItemDescription(entry: QuickOpenEntry): string | null { - return this.allowMatchOnDescription ? types.withUndefinedAsNull(entry.getDescription()) : null; + return this.allowMatchOnDescription ? entry.getDescription() : null; } } @@ -724,8 +724,8 @@ export class EditorHistoryEntryGroup extends QuickOpenEntryGroup { export class EditorHistoryEntry extends EditorQuickOpenEntry { private input: IEditorInput | IResourceInput; private resource: URI | undefined; - private label: string | undefined; - private description?: string; + private label: string | null; + private description: string | null; private dirty: boolean; constructor( @@ -744,8 +744,8 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { if (input instanceof EditorInput) { this.resource = resourceForEditorHistory(input, fileService); - this.label = types.withNullAsUndefined(input.getName()); - this.description = types.withNullAsUndefined(input.getDescription()); + this.label = input.getName(); + this.description = input.getDescription(); this.dirty = input.isDirty(); } else { const resourceInput = input as IResourceInput; @@ -764,7 +764,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { return this.dirty ? 'dirty' : ''; } - getLabel(): string | undefined { + getLabel(): string | null { return this.label; } @@ -778,12 +778,12 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { return nls.localize('entryAriaLabel', "{0}, recently opened", this.getLabel()); } - getDescription(): string | undefined { + getDescription(): string | null { return this.description; } - getResource(): URI | undefined { - return this.resource; + getResource(): URI | null { + return types.withUndefinedAsNull(this.resource); } getInput(): IEditorInput | IResourceInput { @@ -848,7 +848,7 @@ export class RemoveFromEditorHistoryAction extends Action { return { input: h, - iconClasses: getIconClasses(this.modelService, this.modeService, entry.getResource()), + iconClasses: getIconClasses(this.modelService, this.modeService, types.withNullAsUndefined(entry.getResource())), label: entry.getLabel(), description: entry.getDescription() }; diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 75f4afa9f9..a1d0e0caca 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -248,7 +248,7 @@ export class SidebarPart extends CompositePart implements IViewletServi this.contextMenuService.showContextMenu({ getAnchor: () => anchor, getActions: () => contextMenuActions, - getActionViewItem: action => this.actionViewItemProvider(action as Action), + getActionItem: action => this.actionItemProvider(action as Action), actionRunner: activeViewlet.getActionRunner() }); } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index b24b4e9152..064aff3a4d 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -7,11 +7,11 @@ import 'vs/css!./media/views'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IAction, IActionViewItem, ActionRunner, Action } from 'vs/base/common/actions'; +import { IAction, IActionItem, ActionRunner, Action } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; -import { ContextAwareMenuEntryActionViewItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { ContextAwareMenuItemActionItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewsService, ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ViewContainer, ITreeItemLabel, Extensions } from 'vs/workbench/common/views'; import { IViewletViewOptions, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet'; @@ -24,7 +24,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import * as DOM from 'vs/base/browser/dom'; import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; -import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { URI } from 'vs/base/common/uri'; import { dirname, basename } from 'vs/base/common/resources'; import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -87,8 +87,8 @@ export class CustomTreeViewPanel extends ViewletPanel { return [...this.treeView.getSecondaryActions()]; } - getActionViewItem(action: IAction): IActionViewItem | undefined { - return action instanceof MenuItemAction ? new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : undefined; + getActionItem(action: IAction): IActionItem | undefined { + return action instanceof MenuItemAction ? new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : undefined; } getOptimalWidth(): number { @@ -378,11 +378,11 @@ export class CustomTreeView extends Disposable implements ITreeView { } private createTree() { - const actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined; + const actionItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuItemActionItem, action) : undefined; const menus = this._register(this.instantiationService.createInstance(TreeMenus, this.id)); this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); const dataSource = this.instantiationService.createInstance(TreeDataSource, this, (task: Promise) => this.progressService.withProgress({ location: this.viewContainer.id }, () => task)); - const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, menus, this.treeLabels, actionViewItemProvider); + const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, menus, this.treeLabels, actionItemProvider); const controller = this.instantiationService.createInstance(TreeController, this.id, menus); this.tree = this._register(this.instantiationService.createInstance(FileIconThemableWorkbenchTree, this.treeContainer, { dataSource, renderer, controller }, {})); this.tree.contextKeyService.createKey(this.id, true); @@ -645,7 +645,7 @@ class TreeRenderer implements IRenderer { private treeViewId: string, private menus: TreeMenus, private labels: ResourceLabels, - private actionViewItemProvider: IActionViewItemProvider, + private actionItemProvider: IActionItemProvider, @IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService private readonly labelService: ILabelService @@ -668,7 +668,7 @@ class TreeRenderer implements IRenderer { DOM.addClass(resourceLabel.element, 'custom-view-tree-node-item-resourceLabel'); const actionsContainer = DOM.append(resourceLabel.element, DOM.$('.actions')); const actionBar = new ActionBar(actionsContainer, { - actionViewItemProvider: this.actionViewItemProvider, + actionItemProvider: this.actionItemProvider, actionRunner: new MultipleSelectionActionRunner(() => tree.getSelection()) }); @@ -809,10 +809,10 @@ class TreeController extends WorkbenchTreeController { getActions: () => actions, - getActionViewItem: (action) => { + getActionItem: (action) => { const keybinding = this._keybindingService.lookupKeybinding(action.id); if (keybinding) { - return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel() }); + return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel() }); } return undefined; }, diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index b6bdf29506..90bb9e3693 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -13,7 +13,7 @@ import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, a import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { firstIndex } from 'vs/base/common/arrays'; import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { IActionViewItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { Registry } from 'vs/platform/registry/common/platform'; import { prepareActions } from 'vs/workbench/browser/actions'; import { Viewlet, ViewletRegistry, Extensions } from 'vs/workbench/browser/viewlet'; @@ -28,6 +28,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IView } from 'vs/workbench/common/views'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { withNullAsUndefined } from 'vs/base/common/types'; export interface IPanelColors extends IColorMapping { dropBackground?: ColorIdentifier; @@ -126,9 +127,9 @@ export abstract class ViewletPanel extends Panel implements IView { const actions = append(container, $('.actions')); this.toolbar = new ToolBar(actions, this.contextMenuService, { orientation: ActionsOrientation.HORIZONTAL, - actionViewItemProvider: action => this.getActionViewItem(action), + actionItemProvider: action => this.getActionItem(action), ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title), - getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + getKeyBinding: action => withNullAsUndefined(this.keybindingService.lookupKeybinding(action.id)), actionRunner: this.actionRunner }); @@ -179,7 +180,7 @@ export abstract class ViewletPanel extends Panel implements IView { return []; } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { return undefined; } @@ -288,12 +289,12 @@ export class PanelViewlet extends Viewlet { return []; } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (this.isSingleView()) { - return this.panelItems[0].panel.getActionViewItem(action); + return this.panelItems[0].panel.getActionItem(action); } - return super.getActionViewItem(action); + return super.getActionItem(action); } focus(): void { diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index a8b77354df..c078e46b13 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -229,12 +229,12 @@ export interface IEditorQuickOpenEntry { /** * The editor input used for this entry when opening. */ - getInput(): IResourceInput | IEditorInput | undefined; + getInput(): IResourceInput | IEditorInput | null; /** * The editor options used for this entry when opening. */ - getOptions(): IEditorOptions | undefined; + getOptions(): IEditorOptions | null; } /** @@ -250,12 +250,12 @@ export class EditorQuickOpenEntry extends QuickOpenEntry implements IEditorQuick return this._editorService; } - getInput(): IResourceInput | IEditorInput | undefined { - return undefined; + getInput(): IResourceInput | IEditorInput | null { + return null; } - getOptions(): IEditorOptions | undefined { - return undefined; + getOptions(): IEditorOptions | null { + return null; } run(mode: Mode, context: IEntryRunContext): boolean { @@ -301,12 +301,12 @@ export class EditorQuickOpenEntry extends QuickOpenEntry implements IEditorQuick */ export class EditorQuickOpenEntryGroup extends QuickOpenEntryGroup implements IEditorQuickOpenEntry { - getInput(): IEditorInput | IResourceInput | undefined { - return undefined; + getInput(): IEditorInput | IResourceInput | null { + return null; } - getOptions(): IEditorOptions | undefined { - return undefined; + getOptions(): IEditorOptions | null { + return null; } } diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index c12956bb2a..172aeebe0c 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -14,7 +14,7 @@ import { getZoomLevel } from 'vs/base/browser/browser'; import { mark } from 'vs/base/common/performance'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isLinux, isWeb } from 'vs/base/common/platform'; +import { isWindows, isLinux } from 'vs/base/common/platform'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; @@ -270,11 +270,7 @@ export class Workbench extends Layout { ]); addClasses(this.container, ...workbenchClasses); - addClass(document.body, platformClass); // used by our fonts - - if (isWeb) { - addClass(document.body, 'web'); - } + addClasses(document.body, platformClass); // used by our fonts // Apply font aliasing this.setFontAliasing(configurationService); diff --git a/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts index c3a6e06937..2ff7bf89b8 100644 --- a/src/vs/workbench/common/composite.ts +++ b/src/vs/workbench/common/composite.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionItem } from 'vs/base/common/actions'; export interface IComposite { @@ -35,7 +35,7 @@ export interface IComposite { /** * Returns the action item for a specific action. */ - getActionViewItem(action: IAction): IActionViewItem | undefined; + getActionItem(action: IAction): IActionItem | undefined; /** * Returns the underlying control of this composite. diff --git a/src/vs/workbench/common/contextkeys.ts b/src/vs/workbench/common/contextkeys.ts new file mode 100644 index 0000000000..61602d1ee8 --- /dev/null +++ b/src/vs/workbench/common/contextkeys.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; + +export const IsMacContext = new RawContextKey('isMac', isMacintosh); +export const IsLinuxContext = new RawContextKey('isLinux', isLinux); +export const IsWindowsContext = new RawContextKey('isWindows', isWindows); + +export const RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); + +export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); + +export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); + +export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); + +export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined); + +export const WorkspaceFolderCountContext = new RawContextKey('workspaceFolderCount', 0); + +export const RemoteFileDialogContext = new RawContextKey('remoteFileDialogVisible', false); diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index fa7b40bb15..abb91f3dda 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -5,7 +5,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; @@ -144,7 +144,7 @@ export interface IEditorControl extends ICompositeControl { } export interface IFileInputFactory { - createFileInput(resource: URI, encoding: string | undefined, mode: string | undefined, instantiationService: IInstantiationService): IFileEditorInput; + createFileInput(resource: URI, encoding: string | undefined, instantiationService: IInstantiationService): IFileEditorInput; isFileInput(obj: any): obj is IFileEditorInput; } @@ -209,7 +209,7 @@ export interface IUntitledResourceInput extends IBaseResourceInput { /** * Optional language of the untitled resource. */ - mode?: string; + language?: string; /** * Optional contents of the untitled resource. @@ -516,35 +516,19 @@ export interface IEncodingSupport { setEncoding(encoding: string, mode: EncodingMode): void; } -export interface IModeSupport { - - /** - * Sets the language mode of the input. - */ - setMode(mode: string): void; -} - /** * This is a tagging interface to declare an editor input being capable of dealing with files. It is only used in the editor registry * to register this kind of input to the platform. */ -export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeSupport { +export interface IFileEditorInput extends IEditorInput, IEncodingSupport { - /** - * Gets the resource this editor is about. - */ getResource(): URI; /** - * Sets the preferred encoding to use for this input. + * Sets the preferred encodingt to use for this input. */ setPreferredEncoding(encoding: string): void; - /** - * Sets the preferred language mode to use for this input. - */ - setPreferredMode(mode: string): void; - /** * Forces this file input to open as binary instead of text. */ @@ -593,7 +577,7 @@ export class SideBySideEditorInput extends EditorInput { return this.master.revert(); } - getTelemetryDescriptor(): { [key: string]: unknown } { + getTelemetryDescriptor(): object { const descriptor = this.master.getTelemetryDescriptor(); return assign(descriptor, super.getTelemetryDescriptor()); @@ -647,7 +631,8 @@ export class SideBySideEditorInput extends EditorInput { return false; } - return this.details.matches(otherInput.details) && this.master.matches(otherInput.master); + const otherDiffInput = otherInput; + return this.details.matches(otherDiffInput.details) && this.master.matches(otherDiffInput.master); } return false; @@ -1013,9 +998,9 @@ export interface IResourceOptions { filterByScheme?: string | string[]; } -export function toResource(editor: IEditorInput | undefined, options?: IResourceOptions): URI | undefined { +export function toResource(editor: IEditorInput | null | undefined, options?: IResourceOptions): URI | null { if (!editor) { - return undefined; + return null; } if (options && options.supportSideBySide && editor instanceof SideBySideEditorInput) { @@ -1024,7 +1009,7 @@ export function toResource(editor: IEditorInput | undefined, options?: IResource const resource = editor.getResource(); if (!resource || !options || !options.filterByScheme) { - return resource; + return withUndefinedAsNull(resource); } if (Array.isArray(options.filterByScheme) && options.filterByScheme.some(scheme => resource.scheme === scheme)) { @@ -1035,7 +1020,7 @@ export function toResource(editor: IEditorInput | undefined, options?: IResource return resource; } - return undefined; + return null; } export const enum CloseDirection { diff --git a/src/vs/workbench/common/editor/dataUriEditorInput.ts b/src/vs/workbench/common/editor/dataUriEditorInput.ts index ffb78b7d76..467f2317b0 100644 --- a/src/vs/workbench/common/editor/dataUriEditorInput.ts +++ b/src/vs/workbench/common/editor/dataUriEditorInput.ts @@ -68,9 +68,11 @@ export class DataUriEditorInput extends EditorInput { return true; } - // Compare by resource if (otherInput instanceof DataUriEditorInput) { - return otherInput.resource.toString() === this.resource.toString(); + const otherDataUriEditorInput = otherInput; + + // Compare by resource + return otherDataUriEditorInput.resource.toString() === this.resource.toString(); } return false; diff --git a/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts index 18951764ac..6588c7f6fd 100644 --- a/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -67,7 +67,7 @@ export class DiffEditorInput extends SideBySideEditorInput { // If both are text models, return textdiffeditor model if (modifiedEditorModel instanceof BaseTextEditorModel && originalEditorModel instanceof BaseTextEditorModel) { - return new TextDiffEditorModel(originalEditorModel, modifiedEditorModel); + return new TextDiffEditorModel(originalEditorModel, modifiedEditorModel); } // Otherwise return normal diff model diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 7a417fbaef..00633b8523 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorInput, ITextEditorModel, IModeSupport } from 'vs/workbench/common/editor'; +import { EditorInput, ITextEditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -13,18 +13,16 @@ import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorMo * A read-only text editor input whos contents are made of the provided resource that points to an existing * code editor model. */ -export class ResourceEditorInput extends EditorInput implements IModeSupport { +export class ResourceEditorInput extends EditorInput { static readonly ID: string = 'workbench.editors.resourceEditorInput'; - private cachedModel: ResourceEditorModel | null; private modelReference: Promise> | null; constructor( private name: string, private description: string | null, private readonly resource: URI, - private preferredMode: string | undefined, @ITextModelService private readonly textModelResolverService: ITextModelService ) { super(); @@ -64,18 +62,6 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { } } - setMode(mode: string): void { - this.setPreferredMode(mode); - - if (this.cachedModel) { - this.cachedModel.setMode(mode); - } - } - - setPreferredMode(mode: string): void { - this.preferredMode = mode; - } - resolve(): Promise { if (!this.modelReference) { this.modelReference = this.textModelResolverService.createModelReference(this.resource); @@ -84,7 +70,6 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { return this.modelReference.then(ref => { const model = ref.object; - // Ensure the resolved model is of expected type if (!(model instanceof ResourceEditorModel)) { ref.dispose(); this.modelReference = null; @@ -92,13 +77,6 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { return Promise.reject(new Error(`Unexpected model for ResourceInput: ${this.resource}`)); } - this.cachedModel = model; - - // Set mode if we have a preferred mode configured - if (this.preferredMode) { - model.setMode(this.preferredMode); - } - return model; }); } @@ -108,9 +86,11 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { return true; } - // Compare by properties if (otherInput instanceof ResourceEditorInput) { - return otherInput.resource.toString() === this.resource.toString(); + let otherResourceEditorInput = otherInput; + + // Compare by properties + return otherResourceEditorInput.resource.toString() === this.resource.toString(); } return false; @@ -122,8 +102,6 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { this.modelReference = null; } - this.cachedModel = null; - super.dispose(); } } diff --git a/src/vs/workbench/common/editor/resourceEditorModel.ts b/src/vs/workbench/common/editor/resourceEditorModel.ts index da3dae36f3..54dcd62748 100644 --- a/src/vs/workbench/common/editor/resourceEditorModel.ts +++ b/src/vs/workbench/common/editor/resourceEditorModel.ts @@ -19,18 +19,12 @@ export class ResourceEditorModel extends BaseTextEditorModel { @IModelService modelService: IModelService ) { super(modelService, modeService, resource); + + // TODO@Joao: force this class to dispose the underlying model + this.createdEditorModel = true; } isReadonly(): boolean { return true; } - - dispose(): void { - // TODO@Joao: force this class to dispose the underlying model - if (this.textEditorModelHandle) { - this.modelService.destroyModel(this.textEditorModelHandle); - } - - super.dispose(); - } } \ No newline at end of file diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index 046828b73f..f520368338 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -4,21 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import { ITextModel, ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; -import { EditorModel, IModeSupport } from 'vs/workbench/common/editor'; +import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; /** * The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated. */ -export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport { - protected textEditorModelHandle: URI | null; - private createdEditorModel: boolean; +export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel { + protected createdEditorModel: boolean; + + private textEditorModelHandle: URI | null; private modelDisposeListener: IDisposable | null; constructor( @@ -64,25 +64,12 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd abstract isReadonly(): boolean; - setMode(mode: string): void { - if (!this.isResolved()) { - return; - } - - if (!mode || mode === this.textEditorModel.getModeId()) { - return; - } - - this.modelService.setMode(this.textEditorModel, this.modeService.create(mode)); - } - /** - * Creates the text editor model with the provided value, optional preferred mode - * (can be comma separated for multiple values) and optional resource URL. + * Creates the text editor model with the provided value, modeId (can be comma separated for multiple values) and optional resource URL. */ - protected createTextEditorModel(value: ITextBufferFactory, resource: URI | undefined, preferredMode?: string): EditorModel { + protected createTextEditorModel(value: ITextBufferFactory, resource: URI | undefined, modeId?: string): EditorModel { const firstLineText = this.getFirstLineText(value); - const languageSelection = this.getOrCreateMode(resource, this.modeService, preferredMode, firstLineText); + const languageSelection = this.getOrCreateMode(this.modeService, modeId, firstLineText); return this.doCreateTextEditorModel(value, languageSelection, resource); } @@ -96,7 +83,8 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd // Make sure we clean up when this model gets disposed this.registerModelDisposeListener(model); } else { - this.updateTextEditorModel(value, languageSelection.languageIdentifier.language); + this.modelService.updateModel(model, value); + this.modelService.setMode(model, languageSelection); } this.textEditorModelHandle = model.uri; @@ -122,42 +110,28 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd * * @param firstLineText optional first line of the text buffer to set the mode on. This can be used to guess a mode from content. */ - protected getOrCreateMode(resource: URI | undefined, modeService: IModeService, preferredMode: string | undefined, firstLineText?: string): ILanguageSelection { - - // lookup mode via resource path if the provided mode is unspecific - if (!preferredMode || preferredMode === PLAINTEXT_MODE_ID) { - return modeService.createByFilepathOrFirstLine(resource ? resource.path : null, firstLineText); - } - - // otherwise take the preferred mode for granted - return modeService.create(preferredMode); + protected getOrCreateMode(modeService: IModeService, modeId: string | undefined, firstLineText?: string): ILanguageSelection { + return modeService.create(modeId); } /** * Updates the text editor model with the provided value. If the value is the same as the model has, this is a no-op. */ - protected updateTextEditorModel(newValue: ITextBufferFactory, preferredMode?: string): void { - if (!this.isResolved()) { + protected updateTextEditorModel(newValue: ITextBufferFactory): void { + if (!this.textEditorModel) { return; } - // contents this.modelService.updateModel(this.textEditorModel, newValue); - - // mode (only if specific and changed) - if (preferredMode && preferredMode !== PLAINTEXT_MODE_ID && this.textEditorModel.getModeId() !== preferredMode) { - this.modelService.setMode(this.textEditorModel, this.modeService.create(preferredMode)); - } } - createSnapshot(this: IResolvedTextEditorModel): ITextSnapshot; - createSnapshot(this: ITextEditorModel): ITextSnapshot | null; createSnapshot(): ITextSnapshot | null { - if (!this.textEditorModel) { - return null; + const model = this.textEditorModel; + if (model) { + return model.createSnapshot(true /* Preserve BOM */); } - return this.textEditorModel.createSnapshot(true /* preserve BOM */); + return null; } isResolved(): this is IResolvedTextEditorModel { diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index fe68c35210..4928bb315d 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -9,7 +9,7 @@ import { memoize } from 'vs/base/common/decorators'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { basename } from 'vs/base/common/path'; import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; -import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor'; +import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity } from 'vs/workbench/common/editor'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; @@ -20,12 +20,12 @@ import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverServ /** * An editor input to be used for untitled text buffers. */ -export class UntitledEditorInput extends EditorInput implements IEncodingSupport, IModeSupport { +export class UntitledEditorInput extends EditorInput implements IEncodingSupport { static readonly ID: string = 'workbench.editors.untitledEditorInput'; - private cachedModel: UntitledEditorModel | null; - private modelResolve: Promise | null; + private cachedModel: UntitledEditorModel; + private modelResolve?: Promise; private readonly _onDidModelChangeContent: Emitter = this._register(new Emitter()); get onDidModelChangeContent(): Event { return this._onDidModelChangeContent.event; } @@ -36,7 +36,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport constructor( private readonly resource: URI, private readonly _hasAssociatedFilePath: boolean, - private preferredMode: string, + private readonly modeId: string, private readonly initialValue: string, private preferredEncoding: string, @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -58,6 +58,14 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.resource; } + getModeId(): string | null { + if (this.cachedModel) { + return this.cachedModel.getModeId(); + } + + return this.modeId; + } + getName(): string { return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path; } @@ -165,9 +173,9 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport suggestFileName(): string { if (!this.hasAssociatedFilePath) { if (this.cachedModel) { - const mode = this.cachedModel.getMode(); - if (mode !== PLAINTEXT_MODE_ID) { // do not suggest when the mode ID is simple plain text - return suggestFilename(mode, this.getName()); + const modeId = this.cachedModel.getModeId(); + if (modeId !== PLAINTEXT_MODE_ID) { // do not suggest when the mode ID is simple plain text + return suggestFilename(modeId, this.getName()); } } } @@ -191,22 +199,6 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport } } - setMode(mode: string): void { - this.preferredMode = mode; - - if (this.cachedModel) { - this.cachedModel.setMode(mode); - } - } - - getMode(): string | undefined { - if (this.cachedModel) { - return this.cachedModel.getMode(); - } - - return this.preferredMode; - } - resolve(): Promise { // Join a model resolve if we have had one before @@ -222,7 +214,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport } private createModel(): UntitledEditorModel { - const model = this._register(this.instantiationService.createInstance(UntitledEditorModel, this.preferredMode, this.resource, this.hasAssociatedFilePath, this.initialValue, this.preferredEncoding)); + const model = this._register(this.instantiationService.createInstance(UntitledEditorModel, this.modeId, this.resource, this.hasAssociatedFilePath, this.initialValue, this.preferredEncoding)); // re-emit some events from the model this._register(model.onDidChangeContent(() => this._onDidModelChangeContent.fire())); @@ -237,17 +229,18 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return true; } - // Otherwise compare by properties if (otherInput instanceof UntitledEditorInput) { - return otherInput.resource.toString() === this.resource.toString(); + const otherUntitledEditorInput = otherInput; + + // Otherwise compare by properties + return otherUntitledEditorInput.resource.toString() === this.resource.toString(); } return false; } dispose(): void { - this.cachedModel = null; - this.modelResolve = null; + this.modelResolve = undefined; super.dispose(); } diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index abbc289baa..240a4f389e 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -6,8 +6,9 @@ import { IEncodingSupport } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { URI } from 'vs/base/common/uri'; +import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { Event, Emitter } from 'vs/base/common/event'; import { RunOnceScheduler } from 'vs/base/common/async'; @@ -36,7 +37,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin private configuredEncoding: string; constructor( - private readonly preferredMode: string, + private readonly modeId: string, private readonly resource: URI, private _hasAssociatedFilePath: boolean, private readonly initialValue: string, @@ -57,6 +58,14 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin return this._hasAssociatedFilePath; } + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection { + if (!modeId || modeId === PLAINTEXT_MODE_ID) { + return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific + } + + return super.getOrCreateMode(modeService, modeId, firstLineText); + } + private registerListeners(): void { // Config Changes @@ -79,12 +88,12 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin return this.versionId; } - getMode(): string | undefined { + getModeId(): string | null { if (this.textEditorModel) { - return this.textEditorModel.getModeId(); + return this.textEditorModel.getLanguageIdentifier().language; } - return this.preferredMode; + return this.modeId; } getEncoding(): string { @@ -127,44 +136,36 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.contentChangeEventScheduler.schedule(); } - backup(): Promise { - if (this.isResolved()) { - return this.backupFileService.backupResource(this.resource, this.createSnapshot(), this.versionId); - } - - return Promise.resolve(); - } - load(): Promise { // Check for backups first - return this.backupFileService.loadBackupResource(this.resource).then(backupResource => { + return this.backupFileService.loadBackupResource(this.resource).then((backupResource) => { if (backupResource) { return this.backupFileService.resolveBackupContent(backupResource); } - return Promise.resolve(undefined); - }).then(backup => { - const hasBackup = !!backup; + return undefined; + }).then(backupTextBufferFactory => { + const hasBackup = !!backupTextBufferFactory; // untitled associated to file path are dirty right away as well as untitled with content - this.setDirty(this._hasAssociatedFilePath || hasBackup || !!this.initialValue); + this.setDirty(this._hasAssociatedFilePath || hasBackup); let untitledContents: ITextBufferFactory; - if (backup) { - untitledContents = backup.value; + if (backupTextBufferFactory) { + untitledContents = backupTextBufferFactory; } else { untitledContents = createTextBufferFactory(this.initialValue || ''); } // Create text editor model if not yet done if (!this.textEditorModel) { - this.createTextEditorModel(untitledContents, this.resource, this.preferredMode); + this.createTextEditorModel(untitledContents, this.resource, this.modeId); } // Otherwise update else { - this.updateTextEditorModel(untitledContents, this.preferredMode); + this.updateTextEditorModel(untitledContents); } // Encoding diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 319ad7d753..d97aa04106 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -66,7 +66,10 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu if (!this.configuredAutoSaveAfterDelay) { const model = this.textFileService.models.get(event.resource); if (model) { - model.backup(); + const snapshot = model.createSnapshot(); + if (snapshot) { + this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId()); + } } } } @@ -74,7 +77,12 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu private onUntitledModelChanged(resource: Uri): void { if (this.untitledEditorService.isDirty(resource)) { - this.untitledEditorService.loadOrCreate({ resource }).then(model => model.backup()); + this.untitledEditorService.loadOrCreate({ resource }).then(model => { + const snapshot = model.createSnapshot(); + if (snapshot) { + this.backupFileService.backupResource(resource, snapshot, model.getVersionId()); + } + }); } else { this.discardBackup(resource); } diff --git a/src/vs/workbench/contrib/backup/common/backupRestorer.ts b/src/vs/workbench/contrib/backup/common/backupRestorer.ts index 7fc056650e..99662104d3 100644 --- a/src/vs/workbench/contrib/backup/common/backupRestorer.ts +++ b/src/vs/workbench/contrib/backup/common/backupRestorer.ts @@ -78,10 +78,10 @@ export class BackupRestorer implements IWorkbenchContribution { private resolveInput(resource: URI, index: number, hasOpenedEditors: boolean): IResourceInput | IUntitledResourceInput { const options = { pinned: true, preserveFocus: true, inactive: index > 0 || hasOpenedEditors }; - // this is a (weak) strategy to find out if the untitled input had - // an associated file path or not by just looking at the path. and - // if so, we must ensure to restore the local resource it had. - if (resource.scheme === Schemas.untitled && !BackupRestorer.UNTITLED_REGEX.test(resource.path) && BackupRestorer.SQLQUERY_REGEX.test(resource.path)) { // {{SQL CARBON EDIT}} @anthonydresser add sql regex test + // {{SQL CARBON EDIT}} + if (resource.scheme === Schemas.untitled + && !BackupRestorer.UNTITLED_REGEX.test(resource.fsPath) + && !BackupRestorer.SQLQUERY_REGEX.test(resource.fsPath)) { return { resource: toLocalResource(resource, this.environmentService.configuration.remoteAuthority), options, forceUntitled: true }; } diff --git a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts index a1e5e9a8e1..37eed2a399 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts @@ -282,7 +282,7 @@ class ShowAccessibilityHelpAction extends EditorAction { id: 'editor.action.showAccessibilityHelp', label: nls.localize('ShowAccessibilityHelpAction', "Show Accessibility Help"), alias: 'Show Accessibility Help', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.Alt | KeyCode.F1, diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts index 01f17eaef3..1719929f91 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts @@ -17,7 +17,7 @@ class InspectKeyMap extends EditorAction { id: 'workbench.action.inspectKeyMappings', label: nls.localize('workbench.action.inspectKeyMap', "Developer: Inspect Key Mappings"), alias: 'Developer: Inspect Key Mappings', - precondition: undefined + precondition: null }); } diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts index 27896fa037..224867a642 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts @@ -102,7 +102,7 @@ class InspectTMScopes extends EditorAction { id: 'editor.action.inspectTMScopes', label: nls.localize('inspectTMScopes', "Developer: Inspect TM Scopes"), alias: 'Developer: Inspect TM Scopes', - precondition: undefined + precondition: null }); } diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 154d9fc2b5..29d0258307 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -121,7 +121,7 @@ class ToggleWordWrapAction extends EditorAction { id: TOGGLE_WORD_WRAP_ID, label: nls.localize('toggle.wordwrap', "View: Toggle Word Wrap"), alias: 'View: Toggle Word Wrap', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: null, primary: KeyMod.Alt | KeyCode.KEY_Z, diff --git a/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css index 06e13f322f..16f2a7acee 100644 --- a/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css +++ b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css @@ -3,6 +3,43 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .code-inset { - z-index: 10; +.monaco-editor .codelens-decoration { + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; +} + +.monaco-editor .codelens-decoration > span, +.monaco-editor .codelens-decoration > a { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + white-space: nowrap; + vertical-align: sub; +} + +.monaco-editor .codelens-decoration > a { + text-decoration: none; +} + +.monaco-editor .codelens-decoration > a:hover { + text-decoration: underline; + cursor: pointer; +} + +.monaco-editor .codelens-decoration.invisible-cl { + opacity: 0; +} + +@keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } } +@-moz-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } } +@-o-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } } +@-webkit-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } } + +.monaco-editor .codelens-decoration.fadein { + -webkit-animation: fadein 0.5s linear; + -moz-animation: fadein 0.5s linear; + -o-animation: fadein 0.5s linear; + animation: fadein 0.5s linear; } diff --git a/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts index d7acdaf730..9260ee47b2 100644 --- a/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts +++ b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts @@ -155,7 +155,6 @@ export class CodeInsetWidget { } const div = document.createElement('div'); - div.className = 'code-inset'; webview.mountTo(div); webview.onMessage((e: { type: string, payload: any }) => { // The webview contents can use a "size-info" message to report its size. diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 515b57629a..678850bd2c 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import * as modes from 'vs/editor/common/modes'; -import { ActionsOrientation, ActionViewItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionsOrientation, ActionItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Button } from 'vs/base/browser/ui/button/button'; import { Action, IActionRunner } from 'vs/base/common/actions'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; @@ -29,9 +29,9 @@ import { assign } from 'vs/base/common/objects'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown'; +import { DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; -import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction'; +import { ToggleReactionsAction, ReactionAction, ReactionActionItem } from './reactionsAction'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; @@ -165,14 +165,14 @@ export class CommentNode extends Disposable { if (actions.length) { this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { - actionViewItemProvider: action => { + actionItemProvider: action => { if (action.id === ToggleReactionsAction.ID) { - return new DropdownMenuActionViewItem( + return new DropdownMenuActionItem( action, (action).menuActions, this.contextMenuService, action => { - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); }, this.actionRunner!, undefined, @@ -180,7 +180,7 @@ export class CommentNode extends Disposable { () => { return AnchorAlignment.RIGHT; } ); } - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); }, orientation: ActionsOrientation.HORIZONTAL }); @@ -191,7 +191,7 @@ export class CommentNode extends Disposable { } } - actionViewItemProvider(action: Action) { + actionItemProvider(action: Action) { let options = {}; if (action.id === 'comment.delete' || action.id === 'comment.edit' || action.id === ToggleReactionsAction.ID) { options = { label: false, icon: true }; @@ -200,19 +200,19 @@ export class CommentNode extends Disposable { } if (action.id === ReactionAction.ID) { - let item = new ReactionActionViewItem(action); + let item = new ReactionActionItem(action); return item; } else { - let item = new ActionViewItem({}, action, options); + let item = new ActionItem({}, action, options); return item; } } private createReactionPicker2(): ToggleReactionsAction { - let toggleReactionActionViewItem: DropdownMenuActionViewItem; + let toggleReactionActionItem: DropdownMenuActionItem; let toggleReactionAction = this._register(new ToggleReactionsAction(() => { - if (toggleReactionActionViewItem) { - toggleReactionActionViewItem.show(); + if (toggleReactionActionItem) { + toggleReactionActionItem.show(); } }, nls.localize('commentToggleReaction', "Toggle Reaction"))); @@ -235,15 +235,15 @@ export class CommentNode extends Disposable { toggleReactionAction.menuActions = reactionMenuActions; - toggleReactionActionViewItem = new DropdownMenuActionViewItem( + toggleReactionActionItem = new DropdownMenuActionItem( toggleReactionAction, (toggleReactionAction).menuActions, this.contextMenuService, action => { if (action.id === ToggleReactionsAction.ID) { - return toggleReactionActionViewItem; + return toggleReactionActionItem; } - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); }, this.actionRunner!, undefined, @@ -255,10 +255,10 @@ export class CommentNode extends Disposable { } private createReactionPicker(): ToggleReactionsAction { - let toggleReactionActionViewItem: DropdownMenuActionViewItem; + let toggleReactionActionItem: DropdownMenuActionItem; let toggleReactionAction = this._register(new ToggleReactionsAction(() => { - if (toggleReactionActionViewItem) { - toggleReactionActionViewItem.show(); + if (toggleReactionActionItem) { + toggleReactionActionItem.show(); } }, nls.localize('commentAddReaction', "Add Reaction"))); @@ -281,15 +281,15 @@ export class CommentNode extends Disposable { toggleReactionAction.menuActions = reactionMenuActions; - toggleReactionActionViewItem = new DropdownMenuActionViewItem( + toggleReactionActionItem = new DropdownMenuActionItem( toggleReactionAction, (toggleReactionAction).menuActions, this.contextMenuService, action => { if (action.id === ToggleReactionsAction.ID) { - return toggleReactionActionViewItem; + return toggleReactionActionItem; } - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); }, this.actionRunner!, undefined, @@ -303,14 +303,14 @@ export class CommentNode extends Disposable { private createReactionsContainer(commentDetailsContainer: HTMLElement): void { this._reactionActionsContainer = dom.append(commentDetailsContainer, dom.$('div.comment-reactions')); this._reactionsActionBar = new ActionBar(this._reactionActionsContainer, { - actionViewItemProvider: action => { + actionItemProvider: action => { if (action.id === ToggleReactionsAction.ID) { - return new DropdownMenuActionViewItem( + return new DropdownMenuActionItem( action, (action).menuActions, this.contextMenuService, action => { - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); }, this.actionRunner!, undefined, @@ -318,7 +318,7 @@ export class CommentNode extends Disposable { () => { return AnchorAlignment.RIGHT; } ); } - return this.actionViewItemProvider(action as Action); + return this.actionItemProvider(action as Action); } }); this._toDispose.push(this._reactionsActionBar); diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 38140d8bf8..c23a62a120 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -840,7 +840,7 @@ export class NextCommentThreadAction extends EditorAction { id: 'editor.action.nextCommentThreadAction', label: nls.localize('nextCommentThreadAction', "Go to Next Comment Thread"), alias: 'Go to Next Comment Thread', - precondition: undefined, + precondition: null, }); } diff --git a/src/vs/workbench/contrib/comments/browser/reactionsAction.ts b/src/vs/workbench/contrib/comments/browser/reactionsAction.ts index 67876e7ada..8cb61d4d09 100644 --- a/src/vs/workbench/contrib/comments/browser/reactionsAction.ts +++ b/src/vs/workbench/contrib/comments/browser/reactionsAction.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action, IAction } from 'vs/base/common/actions'; import { URI, UriComponents } from 'vs/base/common/uri'; @@ -29,7 +29,7 @@ export class ToggleReactionsAction extends Action { this._menuActions = actions; } } -export class ReactionActionViewItem extends ActionViewItem { +export class ReactionActionItem extends ActionItem { constructor(action: ReactionAction) { super(null, action, {}); } diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 7dca7bd8ac..a78360a712 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -21,7 +21,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { ILabelService } from 'vs/platform/label/common/label'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { TreeResourceNavigator2, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts similarity index 96% rename from src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts rename to src/vs/workbench/contrib/debug/browser/debugActionItems.ts index 7332251718..5cf356aae9 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts @@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { SelectBox, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; -import { SelectActionViewItem, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IDebugService, IDebugSession, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug'; @@ -23,7 +23,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; const $ = dom.$; -export class StartDebugActionViewItem implements IActionViewItem { +export class StartDebugActionItem implements IActionItem { private static readonly SEPARATOR = '─────────'; @@ -171,7 +171,7 @@ export class StartDebugActionViewItem implements IActionViewItem { if (this.options.length === 0) { this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: () => false }); } else { - this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: undefined }); + this.options.push({ label: StartDebugActionItem.SEPARATOR, handler: undefined }); } const disabledIdx = this.options.length - 1; @@ -189,7 +189,7 @@ export class StartDebugActionViewItem implements IActionViewItem { } } -export class FocusSessionActionViewItem extends SelectActionViewItem { +export class FocusSessionActionItem extends SelectActionItem { constructor( action: IAction, @IDebugService protected readonly debugService: IDebugService, diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index 81493c6502..5ce1853970 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -26,7 +26,7 @@ class ToggleBreakpointAction extends EditorAction { id: TOGGLE_BREAKPOINT_ID, label: nls.localize('toggleBreakpointAction', "Debug: Toggle Breakpoint"), alias: 'Debug: Toggle Breakpoint', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyCode.F9, @@ -63,7 +63,7 @@ class ConditionalBreakpointAction extends EditorAction { id: TOGGLE_CONDITIONAL_BREAKPOINT_ID, label: nls.localize('conditionalBreakpointEditorAction', "Debug: Add Conditional Breakpoint..."), alias: 'Debug: Add Conditional Breakpoint...', - precondition: undefined + precondition: null }); } @@ -85,7 +85,7 @@ class LogPointAction extends EditorAction { id: TOGGLE_LOG_POINT_ID, label: nls.localize('logPointEditorAction', "Debug: Add Logpoint..."), alias: 'Debug: Add Logpoint...', - precondition: undefined + precondition: null }); } @@ -288,7 +288,7 @@ class GoToNextBreakpointAction extends GoToBreakpointAction { id: 'editor.debug.action.goToNextBreakpoint', label: nls.localize('goToNextBreakpoint', "Debug: Go To Next Breakpoint"), alias: 'Debug: Go To Next Breakpoint', - precondition: undefined + precondition: null }); } } @@ -299,7 +299,7 @@ class GoToPreviousBreakpointAction extends GoToBreakpointAction { id: 'editor.debug.action.goToPreviousBreakpoint', label: nls.localize('goToPreviousBreakpoint', "Debug: Go To Previous Breakpoint"), alias: 'Debug: Go To Previous Breakpoint', - precondition: undefined + precondition: null }); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 005a4590f3..2ecd3d574e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -14,7 +14,7 @@ import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/act import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IDebugConfiguration, IDebugService, State } from 'vs/workbench/contrib/debug/common/debug'; -import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; +import { FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -27,7 +27,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { INotificationService } from 'vs/platform/notification/common/notification'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { fillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInActionBarActions, MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions'; @@ -86,12 +86,12 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { this.activeActions = []; this.actionBar = this._register(new ActionBar(actionBarContainer, { orientation: ActionsOrientation.HORIZONTAL, - actionViewItemProvider: (action: IAction) => { + actionItemProvider: (action: IAction) => { if (action.id === FocusSessionAction.ID) { - return this.instantiationService.createInstance(FocusSessionActionViewItem, action); + return this.instantiationService.createInstance(FocusSessionActionItem, action); } if (action instanceof MenuItemAction) { - return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, contextMenuService); + return new MenuItemActionItem(action, this.keybindingService, this.notificationService, contextMenuService); } return undefined; diff --git a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts index a823479349..9562f1221c 100644 --- a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts @@ -7,11 +7,11 @@ import 'vs/css!./media/debugViewlet'; import * as nls from 'vs/nls'; import { IAction } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, REPL_ID } from 'vs/workbench/contrib/debug/common/debug'; import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions'; -import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; +import { StartDebugActionItem, FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; @@ -29,14 +29,14 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; export class DebugViewlet extends ViewContainerViewlet { - private startDebugActionViewItem: StartDebugActionViewItem; + private startDebugActionItem: StartDebugActionItem; private progressRunner: IProgressRunner; private breakpointView: ViewletPanel; private panelListeners = new Map(); @@ -80,8 +80,8 @@ export class DebugViewlet extends ViewContainerViewlet { focus(): void { super.focus(); - if (this.startDebugActionViewItem) { - this.startDebugActionViewItem.focus(); + if (this.startDebugActionItem) { + this.startDebugActionItem.focus(); } } @@ -130,16 +130,16 @@ export class DebugViewlet extends ViewContainerViewlet { return [this.selectAndStartAction, this.configureAction, this.toggleReplAction]; } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (action.id === StartAction.ID) { - this.startDebugActionViewItem = this.instantiationService.createInstance(StartDebugActionViewItem, null, action); - return this.startDebugActionViewItem; + this.startDebugActionItem = this.instantiationService.createInstance(StartDebugActionItem, null, action); + return this.startDebugActionItem; } if (action.id === FocusSessionAction.ID) { - return new FocusSessionActionViewItem(action, this.debugService, this.themeService, this.contextViewService, this.configurationService); + return new FocusSessionActionItem(action, this.debugService, this.themeService, this.contextViewService, this.configurationService); } if (action instanceof MenuItemAction) { - return new MenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + return new MenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } return undefined; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index ca293d8b2e..51356eb37f 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -7,7 +7,7 @@ import 'vs/css!vs/workbench/contrib/debug/browser/media/repl'; import * as nls from 'vs/nls'; import { URI as uri } from 'vs/base/common/uri'; import * as errors from 'vs/base/common/errors'; -import { IAction, IActionViewItem, Action } from 'vs/base/common/actions'; +import { IAction, IActionItem, Action } 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'; @@ -39,7 +39,7 @@ import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/wor import { IDecorationOptions } from 'vs/editor/common/editorCommon'; import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; +import { FocusSessionActionItem } from 'vs/workbench/contrib/debug/browser/debugActionItems'; import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'vs/editor/common/modes'; import { first } from 'vs/base/common/arrays'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -309,9 +309,9 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replInput.focus(); } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (action.id === SelectReplAction.ID) { - return this.instantiationService.createInstance(SelectReplActionViewItem, this.selectReplAction); + return this.instantiationService.createInstance(SelectReplActionItem, this.selectReplAction); } return undefined; @@ -852,7 +852,7 @@ class ReplCopyAllAction extends EditorAction { registerEditorAction(AcceptReplInputAction); registerEditorAction(ReplCopyAllAction); -class SelectReplActionViewItem extends FocusSessionActionViewItem { +class SelectReplActionItem extends FocusSessionActionItem { protected getActionContext(_: string, index: number): any { return this.debugService.getModel().getSessions(true)[index]; diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index d3ce1ebe6b..faca5408e2 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -392,7 +392,7 @@ export class DebugService implements IDebugService { return this.showError(err.message).then(() => false); } if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - return this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type.")) + return this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type.")) .then(() => false); } @@ -719,7 +719,7 @@ export class DebugService implements IDebugService { // If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340 let taskStarted = false; - const promise: Promise = this.taskService.getActiveTasks().then(tasks => { + const promise = this.taskService.getActiveTasks().then(tasks => { if (tasks.filter(t => t._id === task._id).length) { // task is already running - nothing to do. return Promise.resolve(null); @@ -733,7 +733,7 @@ export class DebugService implements IDebugService { if (task.configurationProperties.isBackground) { return new Promise((c, e) => once(e => e.kind === TaskEventKind.Inactive && e.taskId === task._id, this.taskService.onDidStateChange)(() => { taskStarted = true; - c(null); + c(undefined); })); } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index 69e86086dd..aafff0590f 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -253,9 +253,9 @@ export class ExtensionEditor extends BaseEditor { const extensionActions = append(details, $('.actions')); this.extensionActionBar = new ActionBar(extensionActions, { animated: false, - actionViewItemProvider: (action: Action) => { + actionItemProvider: (action: Action) => { if (action instanceof ExtensionEditorDropDownAction) { - return action.createActionViewItem(); + return action.createActionItem(); } return undefined; } @@ -565,7 +565,7 @@ export class ExtensionEditor extends BaseEditor { this.contentDisposables.push(webviewElement.onDidFocus(() => this.fireOnDidFocus())); const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement); this.contentDisposables.push(toDisposable(removeLayoutParticipant)); - webviewElement.html = body; + webviewElement.contents = body; this.contentDisposables.push(webviewElement.onDidClickLink(link => { if (!link) { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 91cbd95e75..36fa0a0f36 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -10,7 +10,7 @@ import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; import * as json from 'vs/base/common/json'; -import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionItem, Separator, IActionItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; // {{SQL CARBON EDIT}} @@ -650,15 +650,15 @@ export class UpdateAction extends ExtensionAction { } } -interface IExtensionActionViewItemOptions extends IActionViewItemOptions { +interface IExtensionActionItemOptions extends IActionItemOptions { tabOnlyOnFocus?: boolean; } -export class ExtensionActionViewItem extends ActionViewItem { +export class ExtensionActionItem extends ActionItem { - protected options: IExtensionActionViewItemOptions; + protected options: IExtensionActionItemOptions; - constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) { + constructor(context: any, action: IAction, options: IExtensionActionItemOptions = {}) { super(context, action, options); } @@ -701,15 +701,15 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { super(id, label, cssClass, enabled); } - private _actionViewItem: DropDownMenuActionViewItem; - createActionViewItem(): DropDownMenuActionViewItem { - this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus); - return this._actionViewItem; + private _actionItem: DropDownMenuActionItem; + createActionItem(): DropDownMenuActionItem { + this._actionItem = this.instantiationService.createInstance(DropDownMenuActionItem, this, this.tabOnlyOnFocus); + return this._actionItem; } public run({ actionGroups, disposeActionsOnHide }: { actionGroups: IAction[][], disposeActionsOnHide: boolean }): Promise { - if (this._actionViewItem) { - this._actionViewItem.showMenu(actionGroups, disposeActionsOnHide); + if (this._actionItem) { + this._actionItem.showMenu(actionGroups, disposeActionsOnHide); } return Promise.resolve(); } @@ -720,7 +720,7 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { } } -export class DropDownMenuActionViewItem extends ExtensionActionViewItem { +export class DropDownMenuActionItem extends ExtensionActionItem { private disposables: IDisposable[] = []; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts index 9e4a8883ee..7c0e7547bc 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts @@ -13,7 +13,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { Event } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -81,11 +81,11 @@ export class Renderer implements IPagedRenderer { const author = append(footer, $('.author.ellipsis')); const actionbar = new ActionBar(footer, { animated: false, - actionViewItemProvider: (action: Action) => { + actionItemProvider: (action: Action) => { if (action.id === ManageExtensionAction.ID) { - return (action).createActionViewItem(); + return (action).createActionItem(); } - return new ExtensionActionViewItem(null, action, actionOptions); + return new ExtensionActionItem(null, action, actionOptions); } }); actionbar.onDidRun(({ error }) => error && this.notificationService.error(error)); @@ -192,13 +192,13 @@ export class Renderer implements IPagedRenderer { this.extensionViewState.onFocus(e => { if (areSameExtensions(extension.identifier, e.identifier)) { - data.actionbar.viewItems.forEach(item => (item).setFocus(true)); + data.actionbar.items.forEach(item => (item).setFocus(true)); } }, this, data.extensionDisposables); this.extensionViewState.onBlur(e => { if (areSameExtensions(extension.identifier, e.identifier)) { - data.actionbar.viewItems.forEach(item => (item).setFocus(false)); + data.actionbar.items.forEach(item => (item).setFocus(false)); } }, this, data.extensionDisposables); } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts index 3eb62666d2..8e2c1b6365 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts @@ -54,7 +54,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; -import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; +import { RemoteAuthorityContext } from 'vs/workbench/common/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { ILabelService } from 'vs/platform/label/common/label'; diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index fd4f8a0ec1..5d162abee6 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -23,7 +23,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { SupportsWorkspacesContext } from 'vs/workbench/browser/contextkeys'; +import { SupportsWorkspacesContext } from 'vs/workbench/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; // Contribute Global Actions @@ -160,11 +160,11 @@ function appendEditorTitleContextMenuItem(id: string, title: string, when: Conte } // Editor Title Menu for Conflict Resolution -appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite file contents"), { +appendSaveConflictEditorTitleAction('workbench.files.action.acceptLocalChanges', nls.localize('acceptLocalChanges', "Use your changes and overwrite disk contents"), { light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check.svg`)), dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/check-inverse.svg`)) }, -10, acceptLocalChangesCommand); -appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to file contents"), { +appendSaveConflictEditorTitleAction('workbench.files.action.revertLocalChanges', nls.localize('revertLocalChanges', "Discard your changes and revert to content on disk"), { light: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo.svg`)), dark: URI.parse(require.toUrl(`vs/workbench/contrib/files/browser/media/undo-inverse.svg`)) }, -9, revertLocalChangesCommand); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index 34b7c1c196..028b62f98c 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -871,7 +871,7 @@ class ClipboardContentProvider implements ITextModelContentProvider { ) { } provideTextContent(resource: URI): Promise { - const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.createByFilepathOrFirstLine(resource.path), resource); + const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.create('text/plain'), resource); return Promise.resolve(model); } diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 6940f8e531..e1ecf1ad89 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -11,7 +11,7 @@ import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowO import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ExplorerFocusCondition, TextFileContentProvider, VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files'; +import { ExplorerFocusCondition, FileOnDiskContentProvider, VIEWLET_ID, IExplorerService, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; @@ -44,7 +44,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces'; -import { withUndefinedAsNull } from 'vs/base/common/types'; // {{SQL CARBON EDIT}} import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService'; @@ -349,7 +348,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ if (providerDisposables.length === 0) { registerEditorListener = true; - const provider = instantiationService.createInstance(TextFileContentProvider); + const provider = instantiationService.createInstance(FileOnDiskContentProvider); providerDisposables.push(provider); providerDisposables.push(textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider)); } @@ -358,9 +357,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const uri = getResourceForCommand(resource, accessor.get(IListService), editorService); if (uri && fileService.canHandleResource(uri)) { const name = basename(uri); - const editorLabel = nls.localize('modifiedLabel', "{0} (in file) ↔ {1}", name, name); + const editorLabel = nls.localize('modifiedLabel', "{0} (on disk) ↔ {1}", name, name); - TextFileContentProvider.open(uri, COMPARE_WITH_SAVED_SCHEMA, editorLabel, editorService).then(() => { + editorService.openEditor({ leftResource: resourceToFileOnDisk(COMPARE_WITH_SAVED_SCHEMA, uri), rightResource: uri, label: editorLabel }).then(() => { // Dispose once no more diff editor is opened with the scheme if (registerEditorListener) { @@ -379,7 +378,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -let globalResourceToCompare: URI | undefined; +let globalResourceToCompare: URI | null; let resourceSelectedForCompareContext: IContextKey; CommandsRegistry.registerCommand({ id: SELECT_FOR_COMPARE_COMMAND_ID, @@ -554,9 +553,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const editorService = accessor.get(IEditorService); let resource: URI | null = null; if (resourceOrObject && 'from' in resourceOrObject && resourceOrObject.from === 'menu') { - resource = withUndefinedAsNull(toResource(editorService.activeEditor)); + resource = toResource(editorService.activeEditor); } else { - resource = withUndefinedAsNull(getResourceForCommand(resourceOrObject, accessor.get(IListService), editorService)); + resource = getResourceForCommand(resourceOrObject, accessor.get(IListService), editorService); } // {{SQL CARBON EDIT}} diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index e0f2276691..c768f8fe74 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -42,8 +42,8 @@ import { Schemas } from 'vs/base/common/network'; // Viewlet Action export class OpenExplorerViewletAction extends ShowViewletAction { - static readonly ID = VIEWLET_ID; - static readonly LABEL = nls.localize('showExplorerViewlet', "Show Explorer"); + public static readonly ID = VIEWLET_ID; + public static readonly LABEL = nls.localize('showExplorerViewlet', "Show Explorer"); constructor( id: string, @@ -126,8 +126,8 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Register default file input factory Registry.as(EditorInputExtensions.EditorInputFactories).registerFileInputFactory({ - createFileInput: (resource, encoding, mode, instantiationService): IFileEditorInput => { - return instantiationService.createInstance(FileEditorInput, resource, encoding, mode); + createFileInput: (resource, encoding, instantiationService): IFileEditorInput => { + return instantiationService.createInstance(FileEditorInput, resource, encoding); }, isFileInput: (obj): obj is IFileEditorInput => { @@ -139,7 +139,6 @@ interface ISerializedFileInput { resource: string; resourceJSON: object; encoding?: string; - modeId?: string; } // Register Editor Input Factory @@ -147,27 +146,25 @@ class FileEditorInputFactory implements IEditorInputFactory { constructor() { } - serialize(editorInput: EditorInput): string { + public serialize(editorInput: EditorInput): string { const fileEditorInput = editorInput; const resource = fileEditorInput.getResource(); const fileInput: ISerializedFileInput = { resource: resource.toString(), // Keep for backwards compatibility resourceJSON: resource.toJSON(), - encoding: fileEditorInput.getEncoding(), - modeId: fileEditorInput.getPreferredMode() // only using the preferred user associated mode here if available to not store redundant data + encoding: fileEditorInput.getEncoding() }; return JSON.stringify(fileInput); } - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { + public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { return instantiationService.invokeFunction(accessor => { const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); const resource = !!fileInput.resourceJSON ? URI.revive(fileInput.resourceJSON) : URI.parse(fileInput.resource); const encoding = fileInput.encoding; - const mode = fileInput.modeId; - return accessor.get(IEditorService).createInput({ resource, encoding, mode, forceFile: true }) as FileEditorInput; + return accessor.get(IEditorService).createInput({ resource, encoding, forceFile: true }) as FileEditorInput; }); } } @@ -329,11 +326,6 @@ configurationRegistry.registerConfiguration({ 'type': 'number', 'default': 4096, 'markdownDescription': nls.localize('maxMemoryForLargeFilesMB', "Controls the memory available to VS Code after restart when trying to open large files. Same effect as specifying `--max-memory=NEWSIZE` on the command line.") - }, - 'files.simpleDialog.enable': { - 'type': 'boolean', - 'description': nls.localize('files.simpleDialog.enable', "Enables the simple file dialog. The simple file dialog replaces the system file dialog when enabled."), - 'default': false, } } }); diff --git a/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts index ca307d36a5..e5018b2535 100644 --- a/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -14,7 +14,7 @@ import { coalesce } from 'vs/base/common/arrays'; // Commands can get exeucted from a command pallete, from a context menu or from some list using a keybinding // To cover all these cases we need to properly compute the resource on which the command is being executed -export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | undefined { +export function getResourceForCommand(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): URI | null { if (URI.isUri(resource)) { return resource; } @@ -41,7 +41,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe } } - return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : undefined; + return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null; } export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array { diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index b58543f9c8..d609824caf 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -19,7 +19,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { TextFileContentProvider } from 'vs/workbench/contrib/files/common/files'; +import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { IModelService } from 'vs/editor/common/services/modelService'; import { SAVE_FILE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands'; @@ -39,7 +39,7 @@ export const CONFLICT_RESOLUTION_SCHEME = 'conflictResolution'; const LEARN_MORE_DIRTY_WRITE_IGNORE_KEY = 'learnMoreDirtyWriteError'; -const conflictEditorHelp = nls.localize('userGuide', "Use the actions in the editor tool bar to either undo your changes or overwrite the content of the file with your changes."); +const conflictEditorHelp = nls.localize('userGuide', "Use the actions in the editor tool bar to either undo your changes or overwrite the content on disk with your changes."); // A handler for save error happening with conflict resolution actions export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, IWorkbenchContribution { @@ -61,7 +61,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I this.messages = new ResourceMap(); this.conflictResolutionContext = new RawContextKey(CONFLICT_RESOLUTION_CONTEXT, false).bindTo(contextKeyService); - const provider = this._register(instantiationService.createInstance(TextFileContentProvider)); + const provider = this._register(instantiationService.createInstance(FileOnDiskContentProvider)); this._register(textModelService.registerTextModelContentProvider(CONFLICT_RESOLUTION_SCHEME, provider)); // Hook into model @@ -125,7 +125,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I // Otherwise show the message that will lead the user into the save conflict editor. else { - message = nls.localize('staleSaveError', "Failed to save '{0}': The content of the file is newer. Please compare your version with the file contents.", basename(resource)); + message = nls.localize('staleSaveError', "Failed to save '{0}': The content on disk is newer. Please compare your version with the one on disk.", basename(resource)); actions.primary!.push(this.instantiationService.createInstance(ResolveSaveConflictAction, model)); } @@ -244,9 +244,16 @@ class ResolveSaveConflictAction extends Action { if (!this.model.isDisposed()) { const resource = this.model.getResource(); const name = basename(resource); - const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.environmentService.appNameLong); + const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (on disk) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.environmentService.appNameLong); - return TextFileContentProvider.open(resource, CONFLICT_RESOLUTION_SCHEME, editorLabel, this.editorService, { pinned: true }).then(() => { + return this.editorService.openEditor( + { + leftResource: resourceToFileOnDisk(CONFLICT_RESOLUTION_SCHEME, resource), + rightResource: resource, + label: editorLabel, + options: { pinned: true } + } + ).then(() => { if (this.storageService.getBoolean(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, StorageScope.GLOBAL)) { return; // return if this message is ignored } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 13edb5fef1..f2586ca831 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -35,7 +35,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; -import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { onUnexpectedError } from 'vs/base/common/errors'; diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 06dc9f65da..36e110e1fe 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -30,7 +30,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { DirtyEditorContext, OpenEditorsGroupContext } from 'vs/workbench/contrib/files/browser/fileCommands'; import { ResourceContextKey } from 'vs/workbench/common/resources'; @@ -41,7 +41,7 @@ import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { memoize } from 'vs/base/common/decorators'; import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { URI } from 'vs/base/common/uri'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined } from 'vs/base/common/types'; const $ = dom.$; @@ -245,7 +245,7 @@ export class OpenEditorsView extends ViewletPanel { const element = e.elements.length ? e.elements[0] : undefined; if (element instanceof OpenEditor) { this.dirtyEditorFocusedContext.set(this.textFileService.isDirty(withNullAsUndefined(element.getResource()))); - this.resourceContext.set(withUndefinedAsNull(element.getResource())); + this.resourceContext.set(element.getResource()); } else if (!!element) { this.groupFocusedContext.set(true); } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 89b9b9c861..39be01d3de 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -24,11 +24,8 @@ import { ILabelService } from 'vs/platform/label/common/label'; */ export class FileEditorInput extends EditorInput implements IFileEditorInput { private preferredEncoding: string; - private preferredMode: string; - private forceOpenAsBinary: boolean; private forceOpenAsText: boolean; - private textModelReference: Promise> | null; private name: string; @@ -38,7 +35,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { constructor( private resource: URI, preferredEncoding: string | undefined, - preferredMode: string | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextFileService private readonly textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, @@ -50,10 +46,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { this.setPreferredEncoding(preferredEncoding); } - if (preferredMode) { - this.setPreferredMode(preferredMode); - } - this.registerListeners(); } @@ -97,7 +89,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { } setEncoding(encoding: string, mode: EncodingMode): void { - this.setPreferredEncoding(encoding); + this.preferredEncoding = encoding; const textModel = this.textFileService.models.get(this.resource); if (textModel) { @@ -110,24 +102,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { this.forceOpenAsText = true; // encoding is a good hint to open the file as text } - getPreferredMode(): string | undefined { - return this.preferredMode; - } - - setMode(mode: string): void { - this.setPreferredMode(mode); - - const textModel = this.textFileService.models.get(this.resource); - if (textModel) { - textModel.setMode(mode); - } - } - - setPreferredMode(mode: string): void { - this.preferredMode = mode; - this.forceOpenAsText = true; // mode is a good hint to open the file as text - } - setForceOpenAsText(): void { this.forceOpenAsText = true; this.forceOpenAsBinary = false; @@ -219,7 +193,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private decorateLabel(label: string): string { const model = this.textFileService.models.get(this.resource); if (model && model.hasState(ModelState.ORPHAN)) { - return localize('orphanedFile', "{0} (deleted)", label); + return localize('orphanedFile', "{0} (deleted from disk)", label); } if (model && model.isReadonly()) { @@ -277,7 +251,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { // Resolve as text return this.textFileService.models.loadOrCreate(this.resource, { - mode: this.preferredMode, encoding: this.preferredEncoding, reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model allowBinary: this.forceOpenAsText, diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 063b5d0228..4460a70b2b 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -23,8 +23,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { once } from 'vs/base/common/functional'; -import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; /** * Explorer viewlet id. @@ -60,8 +58,8 @@ export interface IExplorerService { isCut(stat: ExplorerItem): boolean; /** - * Selects and reveal the file element provided by the given resource if its found in the explorer. - * Will try to resolve the path in case the explorer is not yet expanded to the file yet. + * Selects and reveal the file element provided by the given resource if its found in the explorer. Will try to + * resolve the path from the disk in case the explorer is not yet expanded to the file yet. */ select(resource: URI, reveal?: boolean): Promise; } @@ -133,7 +131,15 @@ export const SortOrderConfiguration = { export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified'; -export class TextFileContentProvider implements ITextModelContentProvider { +export function resourceToFileOnDisk(scheme: string, resource: URI): URI { + return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) }); +} + +export function fileOnDiskToResource(resource: URI): URI { + return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null }); +} + +export class FileOnDiskContentProvider implements ITextModelContentProvider { private fileWatcherDisposable: IDisposable | undefined; constructor( @@ -141,34 +147,16 @@ export class TextFileContentProvider implements ITextModelContentProvider { @IFileService private readonly fileService: IFileService, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService - ) { } - - static open(resource: URI, scheme: string, label: string, editorService: IEditorService, options?: ITextEditorOptions): Promise { - return editorService.openEditor( - { - leftResource: TextFileContentProvider.resourceToTextFile(scheme, resource), - rightResource: resource, - label, - options - } - ).then(); - } - - private static resourceToTextFile(scheme: string, resource: URI): URI { - return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) }); - } - - private static textFileToResource(resource: URI): URI { - return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null }); + ) { } provideTextContent(resource: URI): Promise { - const savedFileResource = TextFileContentProvider.textFileToResource(resource); + const savedFileResource = fileOnDiskToResource(resource); - // Make sure our text file is resolved up to date + // Make sure our file from disk is resolved up to date return this.resolveEditorModel(resource).then(codeEditorModel => { - // Make sure to keep contents up to date when it changes + // Make sure to keep contents on disk up to date when it changes if (!this.fileWatcherDisposable) { this.fileWatcherDisposable = this.fileService.onFileChanges(changes => { if (changes.contains(savedFileResource, FileChangeType.UPDATED)) { @@ -191,20 +179,20 @@ export class TextFileContentProvider implements ITextModelContentProvider { private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise; private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise; private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise { - const savedFileResource = TextFileContentProvider.textFileToResource(resource); + const savedFileResource = fileOnDiskToResource(resource); return this.textFileService.readStream(savedFileResource).then(content => { let codeEditorModel = this.modelService.getModel(resource); if (codeEditorModel) { this.modelService.updateModel(codeEditorModel, content.value); } else if (createAsNeeded) { - const textFileModel = this.modelService.getModel(savedFileResource); + const fileOnDiskModel = this.modelService.getModel(savedFileResource); let languageSelector: ILanguageSelection; - if (textFileModel) { - languageSelector = this.modeService.create(textFileModel.getModeId()); + if (fileOnDiskModel) { + languageSelector = this.modeService.create(fileOnDiskModel.getModeId()); } else { - languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.path); + languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.fsPath); } codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource); @@ -258,7 +246,7 @@ export class OpenEditor implements IEditorIdentifier { return this.editor.isDirty(); } - public getResource(): URI | undefined { + public getResource(): URI | null { return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER }); } } diff --git a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts index 79d83c6f5d..24f041e134 100644 --- a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts @@ -16,7 +16,6 @@ import { FileOperationResult, FileOperationError } from 'vs/platform/files/commo import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; -import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; class ServiceAccessor { constructor( @@ -37,10 +36,10 @@ suite('Files - FileEditorInput', () => { accessor = instantiationService.createInstance(ServiceAccessor); }); - test('Basics', async function () { - let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined); - const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), undefined, undefined); - const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), undefined, undefined); + test('Basics', function () { + let input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined); + const otherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/otherfile.js'), undefined); + const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource.call(this, 'foo/bar/file.js'), undefined); assert(input.matches(input)); assert(input.matches(otherInputSame)); @@ -55,65 +54,52 @@ suite('Files - FileEditorInput', () => { assert.strictEqual(toResource.call(this, '/foo/bar/file.js').fsPath, input.getResource().fsPath); assert(input.getResource() instanceof URI); - input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar.html'), undefined, undefined); + input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar.html'), undefined); - const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined); - const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined); + const inputToResolve: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined); + const sameOtherInput: FileEditorInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined); - let resolved = await inputToResolve.resolve(); - assert.ok(inputToResolve.isResolved()); + return inputToResolve.resolve().then(resolved => { + assert.ok(inputToResolve.isResolved()); - const resolvedModelA = resolved; - resolved = await inputToResolve.resolve(); - assert(resolvedModelA === resolved); // OK: Resolved Model cached globally per input + const resolvedModelA = resolved; + return inputToResolve.resolve().then(resolved => { + assert(resolvedModelA === resolved); // OK: Resolved Model cached globally per input - const otherResolved = await sameOtherInput.resolve(); - assert(otherResolved === resolvedModelA); // OK: Resolved Model cached globally per input - inputToResolve.dispose(); + return sameOtherInput.resolve().then(otherResolved => { + assert(otherResolved === resolvedModelA); // OK: Resolved Model cached globally per input - resolved = await inputToResolve.resolve(); - assert(resolvedModelA === resolved); // Model is still the same because we had 2 clients - inputToResolve.dispose(); - sameOtherInput.dispose(); - resolvedModelA.dispose(); + inputToResolve.dispose(); - resolved = await inputToResolve.resolve(); - assert(resolvedModelA !== resolved); // Different instance, because input got disposed + return inputToResolve.resolve().then(resolved => { + assert(resolvedModelA === resolved); // Model is still the same because we had 2 clients - const stat = (resolved as TextFileEditorModel).getStat(); - resolved = await inputToResolve.resolve(); - await timeout(0); - assert(stat !== (resolved as TextFileEditorModel).getStat()); // Different stat, because resolve always goes to the server for refresh - }); + inputToResolve.dispose(); + sameOtherInput.dispose(); - test('preferred mode', async function () { - const mode = 'file-input-test'; - ModesRegistry.registerLanguage({ - id: mode, + resolvedModelA.dispose(); + + return inputToResolve.resolve().then(resolved => { + assert(resolvedModelA !== resolved); // Different instance, because input got disposed + + let stat = (resolved as TextFileEditorModel).getStat(); + return inputToResolve.resolve().then(resolved => { + return timeout(0).then(() => { // due to file editor input using `reload: { async: true }` + assert(stat !== (resolved as TextFileEditorModel).getStat()); // Different stat, because resolve always goes to the server for refresh + }); + }); + }); + }); + }); + }); }); - - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, mode); - assert.equal(input.getPreferredMode(), mode); - - const model = await input.resolve() as TextFileEditorModel; - assert.equal(model.textEditorModel!.getModeId(), mode); - - input.setMode('text'); - assert.equal(input.getPreferredMode(), 'text'); - assert.equal(model.textEditorModel!.getModeId(), PLAINTEXT_MODE_ID); - - const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), undefined, undefined); - input2.setPreferredMode(mode); - - const model2 = await input2.resolve() as TextFileEditorModel; - assert.equal(model2.textEditorModel!.getModeId(), mode); }); test('matches', function () { - const input1 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); - const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); - const input3 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/other.js'), undefined, undefined); - const input2Upper = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/UPDATEFILE.js'), undefined, undefined); + const input1 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); + const input2 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); + const input3 = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/other.js'), undefined); + const input2Upper = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/UPDATEFILE.js'), undefined); assert.strictEqual(input1.matches(null), false); assert.strictEqual(input1.matches(input1), true); @@ -123,58 +109,70 @@ suite('Files - FileEditorInput', () => { assert.strictEqual(input1.matches(input2Upper), false); }); - test('getEncoding/setEncoding', async function () { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + test('getEncoding/setEncoding', function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); input.setEncoding('utf16', EncodingMode.Encode); assert.equal(input.getEncoding(), 'utf16'); - const resolved = await input.resolve() as TextFileEditorModel; - assert.equal(input.getEncoding(), resolved.getEncoding()); - resolved.dispose(); + return input.resolve().then((resolved: TextFileEditorModel) => { + assert.equal(input.getEncoding(), resolved.getEncoding()); + + resolved.dispose(); + }); }); - test('save', async function () { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + test('save', function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); - const resolved = await input.resolve() as TextFileEditorModel; - resolved.textEditorModel!.setValue('changed'); - assert.ok(input.isDirty()); + return input.resolve().then((resolved: TextFileEditorModel) => { + resolved.textEditorModel!.setValue('changed'); + assert.ok(input.isDirty()); - await input.save(); - assert.ok(!input.isDirty()); - resolved.dispose(); + return input.save().then(() => { + assert.ok(!input.isDirty()); + + resolved.dispose(); + }); + }); }); - test('revert', async function () { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + test('revert', function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); - const resolved = await input.resolve() as TextFileEditorModel; - resolved.textEditorModel!.setValue('changed'); - assert.ok(input.isDirty()); + return input.resolve().then((resolved: TextFileEditorModel) => { + resolved.textEditorModel!.setValue('changed'); + assert.ok(input.isDirty()); - await input.revert(); - assert.ok(!input.isDirty()); - resolved.dispose(); + return input.revert().then(() => { + assert.ok(!input.isDirty()); + + resolved.dispose(); + }); + }); }); - test('resolve handles binary files', async function () { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + test('resolve handles binary files', function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); accessor.textFileService.setResolveTextContentErrorOnce(new TextFileOperationError('error', TextFileOperationResult.FILE_IS_BINARY)); - const resolved = await input.resolve(); - assert.ok(resolved); - resolved.dispose(); + return input.resolve().then(resolved => { + assert.ok(resolved); + + resolved.dispose(); + }); }); - test('resolve handles too large files', async function () { - const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + test('resolve handles too large files', function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined); accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_TOO_LARGE)); - const resolved = await input.resolve(); - assert.ok(resolved); - resolved.dispose(); + return input.resolve().then(resolved => { + assert.ok(resolved); + + resolved.dispose(); + }); }); }); diff --git a/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts b/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts index c356c32c1c..f53616a234 100644 --- a/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts +++ b/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { workbenchInstantiationService, TestFileService } from 'vs/workbench/test/workbenchTestServices'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { TextFileContentProvider } from 'vs/workbench/contrib/files/common/files'; +import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; @@ -29,10 +29,10 @@ suite('Files - FileOnDiskContentProvider', () => { }); test('provideTextContent', async () => { - const provider = instantiationService.createInstance(TextFileContentProvider); + const provider = instantiationService.createInstance(FileOnDiskContentProvider); const uri = URI.parse('testFileOnDiskContentProvider://foo'); - const content = await provider.provideTextContent(uri.with({ scheme: 'conflictResolution', query: JSON.stringify({ scheme: uri.scheme }) })); + const content = await provider.provideTextContent(resourceToFileOnDisk('conflictResolution', uri)); assert.equal(snapshotToString(content.createSnapshot()), 'Hello Html'); assert.equal(accessor.fileService.getLastReadFileUri().toString(), uri.toString()); diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index bc8199aa45..4963549901 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -201,34 +201,19 @@ async function showFormatterPick(accessor: ServicesAccessor, model: ITextModel, const overrides = { resource: model.uri, overrideIdentifier: model.getModeId() }; const defaultFormatter = configService.getValue(DefaultFormatter.configName, overrides); - let defaultFormatterPick: IIndexedPick | undefined; - const picks = formatters.map((provider, index) => { - const isDefault = ExtensionIdentifier.equals(provider.extensionId, defaultFormatter); - const pick = { + return { index, label: provider.displayName || '', - description: isDefault ? nls.localize('def', "(default)") : undefined, + description: ExtensionIdentifier.equals(provider.extensionId, defaultFormatter) ? nls.localize('def', "(default)") : undefined, }; - - if (isDefault) { - // autofocus default pick - defaultFormatterPick = pick; - } - - return pick; }); const configurePick: IQuickPickItem = { label: nls.localize('config', "Configure Default Formatter...") }; - const pick = await quickPickService.pick([...picks, { type: 'separator' }, configurePick], - { - placeHolder: nls.localize('format.placeHolder', "Select a formatter"), - activeItem: defaultFormatterPick - } - ); + const pick = await quickPickService.pick([...picks, { type: 'separator' }, configurePick], { placeHolder: nls.localize('format.placeHolder', "Select a formatter") }); if (!pick) { // dismissed return undefined; diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 08555275ac..346939d3aa 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -7,14 +7,14 @@ import 'vs/css!./media/markers'; import { URI } from 'vs/base/common/uri'; import * as dom from 'vs/base/browser/dom'; -import { IAction, IActionViewItem, Action } from 'vs/base/common/actions'; +import { IAction, IActionItem, Action } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Panel } from 'vs/workbench/browser/panel'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import Constants from 'vs/workbench/contrib/markers/browser/constants'; import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/contrib/markers/browser/markersModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { MarkersFilterActionViewItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; +import { MarkersFilterActionItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations'; @@ -34,7 +34,7 @@ import { deepClone } from 'vs/base/common/objects'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/browser/markersTreeViewer'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { Separator, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -74,7 +74,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private actions: IAction[]; private collapseAllAction: IAction; private filterAction: MarkersFilterAction; - private filterInputActionViewItem: MarkersFilterActionViewItem; + private filterInputActionItem: MarkersFilterActionItem; private treeContainer: HTMLElement; private messageBoxContainer: HTMLElement; @@ -152,8 +152,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { public layout(dimension: dom.Dimension): void { this.treeContainer.style.height = `${dimension.height}px`; this.tree.layout(dimension.height, dimension.width); - if (this.filterInputActionViewItem) { - this.filterInputActionViewItem.toggleLayout(dimension.width < 1200); + if (this.filterInputActionItem) { + this.filterInputActionItem.toggleLayout(dimension.width < 1200); } } @@ -166,8 +166,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } public focusFilter(): void { - if (this.filterInputActionViewItem) { - this.filterInputActionViewItem.focus(); + if (this.filterInputActionItem) { + this.filterInputActionItem.focus(); } } @@ -358,8 +358,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { // move focus to input, whenever a key is pressed in the panel container this._register(domEvent(parent, 'keydown')(e => { - if (this.filterInputActionViewItem && this.keybindingService.mightProducePrintableCharacter(new StandardKeyboardEvent(e))) { - this.filterInputActionViewItem.focus(); + if (this.filterInputActionItem && this.keybindingService.mightProducePrintableCharacter(new StandardKeyboardEvent(e))) { + this.filterInputActionItem.focus(); } })); @@ -624,10 +624,10 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.contextMenuService.showContextMenu({ getAnchor: () => e.anchor!, getActions: () => this.getMenuActions(element), - getActionViewItem: (action) => { + getActionItem: (action) => { const keybinding = this.keybindingService.lookupKeybinding(action.id); if (keybinding) { - return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel() }); + return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel() }); } return undefined; }, @@ -671,12 +671,12 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { return this.tree.getFocus()[0]; } - public getActionViewItem(action: IAction): IActionViewItem | undefined { + public getActionItem(action: IAction): IActionItem | undefined { if (action.id === MarkersFilterAction.ID) { - this.filterInputActionViewItem = this.instantiationService.createInstance(MarkersFilterActionViewItem, this.filterAction, this); - return this.filterInputActionViewItem; + this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction, this); + return this.filterInputActionItem; } - return super.getActionViewItem(action); + return super.getActionItem(action); } getFilterOptions(): FilterOptions { diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index 1023c3e43a..56883723e6 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -19,7 +19,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; import { IMarkersWorkbenchService } from 'vs/workbench/contrib/markers/browser/markers'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { BaseActionViewItem, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionItem, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; @@ -115,7 +115,7 @@ export interface IMarkerFilterController { getFilterStats(): { total: number, filtered: number }; } -export class MarkersFilterActionViewItem extends BaseActionViewItem { +export class MarkersFilterActionItem extends BaseActionItem { private delayedFilterUpdate: Delayer; private container: HTMLElement; @@ -331,7 +331,7 @@ export class QuickFixAction extends Action { } } -export class QuickFixActionViewItem extends ActionViewItem { +export class QuickFixActionItem extends ActionItem { constructor(action: QuickFixAction, @IContextMenuService private readonly contextMenuService: IContextMenuService, diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index a2a4026869..6c20daaa90 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -17,7 +17,7 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { QuickFixAction, QuickFixActionViewItem } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; +import { QuickFixAction, QuickFixActionItem } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; import { ILabelService } from 'vs/platform/label/common/label'; import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; @@ -253,7 +253,7 @@ class MarkerWidget extends Disposable { ) { super(); this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), { - actionViewItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionViewItem, action) : undefined + actionItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionItem, action) : undefined })); this.icon = dom.append(parent, dom.$('.icon')); this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')))); @@ -290,9 +290,9 @@ class MarkerWidget extends Disposable { } }, this, this.disposables); quickFixAction.onShowQuickFixes(() => { - const quickFixActionViewItem = this.actionBar.viewItems[0]; - if (quickFixActionViewItem) { - quickFixActionViewItem.showQuickFixes(); + const quickFixActionItem = this.actionBar.items[0]; + if (quickFixActionItem) { + quickFixActionItem.showQuickFixes(); } }, this, this.disposables); } diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index 402cb768f6..c988a17702 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -28,7 +28,7 @@ export class LogViewerInput extends ResourceEditorInput { constructor(private outputChannelDescriptor: IFileOutputChannelDescriptor, @ITextModelService textModelResolverService: ITextModelService ) { - super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), undefined, textModelResolverService); + super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), textModelResolverService); } public getTypeId(): string { diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index cd2e5cac4e..c356957fed 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IAction, Action } from 'vs/base/common/actions'; import { IOutputService, OUTPUT_PANEL_ID, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; -import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; @@ -125,7 +125,7 @@ export class SwitchOutputAction extends Action { } } -export class SwitchOutputActionViewItem extends SelectActionViewItem { +export class SwitchOutputActionItem extends SelectActionItem { private static readonly SEPARATOR = '─────────'; @@ -168,7 +168,7 @@ export class SwitchOutputActionViewItem extends SelectActionViewItem { this.logChannels = groups[1] || []; const showSeparator = this.outputChannels.length && this.logChannels.length; const separatorIndex = showSeparator ? this.outputChannels.length : -1; - const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionViewItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; + const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; let selected = 0; const activeChannel = this.outputService.getActiveChannel(); if (activeChannel) { diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index eedd3fedab..2cbcd1b399 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/output'; import * as nls from 'vs/nls'; import { Action, IAction } from 'vs/base/common/actions'; -import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -18,7 +18,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { AbstractTextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; import { OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT } from 'vs/workbench/contrib/output/common/output'; -import { SwitchOutputAction, SwitchOutputActionViewItem, ClearOutputAction, ToggleOrSetOutputScrollLockAction, OpenLogOutputFile } from 'vs/workbench/contrib/output/browser/outputActions'; +import { SwitchOutputAction, SwitchOutputActionItem, ClearOutputAction, ToggleOrSetOutputScrollLockAction, OpenLogOutputFile } from 'vs/workbench/contrib/output/browser/outputActions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -75,12 +75,12 @@ export class OutputPanel extends AbstractTextResourceEditor { return this.actions; } - public getActionViewItem(action: Action): IActionViewItem | undefined { + public getActionItem(action: Action): IActionItem | undefined { if (action.id === SwitchOutputAction.ID) { - return this.instantiationService.createInstance(SwitchOutputActionViewItem, action); + return this.instantiationService.createInstance(SwitchOutputActionItem, action); } - return super.getActionViewItem(action); + return super.getActionItem(action); } protected getConfigurationOverrides(): IEditorOptions { @@ -95,7 +95,7 @@ export class OutputPanel extends AbstractTextResourceEditor { options.renderLineHighlight = 'none'; options.minimap = { enabled: false }; - const outputConfig = this.baseConfigurationService.getValue<{}>('[Log]'); + const outputConfig = this.baseConfigurationService.getValue('[Log]'); if (outputConfig) { if (outputConfig['editor.minimap.enabled']) { options.minimap = { enabled: true }; diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index 42466560e3..c0f4b2ee2a 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -244,7 +244,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private createInput(channel: IOutputChannel): ResourceEditorInput { const resource = URI.from({ scheme: OUTPUT_SCHEME, path: channel.id }); - return this.instantiationService.createInstance(ResourceEditorInput, nls.localize('output', "{0} - Output", channel.label), nls.localize('channel', "Output channel for '{0}'", channel.label), resource, undefined); + return this.instantiationService.createInstance(ResourceEditorInput, nls.localize('output', "{0} - Output", channel.label), nls.localize('channel', "Output channel for '{0}'", channel.label), resource); } private saveState(): void { diff --git a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts index cc5ae90899..0317fed422 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts @@ -52,7 +52,6 @@ export class PerfviewInput extends ResourceEditorInput { localize('name', "Startup Performance"), null, PerfviewInput.Uri, - undefined, textModelResolverService ); } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 2b253a63b9..2363faf286 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -9,7 +9,7 @@ import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { OS } from 'vs/base/common/platform'; import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; -import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox'; +import { CheckboxActionItem } from 'vs/base/browser/ui/checkbox/checkbox'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; import { IAction, Action } from 'vs/base/common/actions'; @@ -372,12 +372,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.actionBar = this._register(new ActionBar(this.actionsContainer, { animated: false, - actionViewItemProvider: (action: Action) => { + actionItemProvider: (action: Action) => { if (action.id === this.sortByPrecedenceAction.id) { - return new CheckboxActionViewItem(null, action); + return new CheckboxActionItem(null, action); } if (action.id === this.recordKeysAction.id) { - return new CheckboxActionViewItem(null, action); + return new CheckboxActionItem(null, action); } return undefined; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index b062bfec4f..e8fdb3edf7 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -154,14 +154,14 @@ export class PreferencesEditor extends BaseEditor { this.preferencesRenderers.editFocusedPreference(); } - setInput(newInput: EditorInput, options: SettingsEditorOptions, token: CancellationToken): Promise { + setInput(newInput: PreferencesEditorInput, options: SettingsEditorOptions, token: CancellationToken): Promise { this.defaultSettingsEditorContextKey.set(true); this.defaultSettingsJSONEditorContextKey.set(true); if (options && options.query) { this.focusSearch(options.query); } - return super.setInput(newInput, options, token).then(() => this.updateInput(newInput as PreferencesEditorInput, options, token)); + return super.setInput(newInput, options, token).then(() => this.updateInput(newInput, options, token)); } layout(dimension: DOM.Dimension): void { diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index 87b297db14..c013254ed7 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -5,7 +5,7 @@ import * as DOM from 'vs/base/browser/dom'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActionBar, ActionsOrientation, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, ActionsOrientation, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IInputOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { Widget } from 'vs/base/browser/ui/widget'; import { Action, IAction } from 'vs/base/common/actions'; @@ -291,7 +291,7 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { } } -export class FolderSettingsActionViewItem extends BaseActionViewItem { +export class FolderSettingsActionItem extends BaseActionItem { private _folder: IWorkspaceFolder | null; private _folderSettingCounts = new Map(); @@ -427,7 +427,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { this.contextMenuService.showContextMenu({ getAnchor: () => this.container, getActions: () => this.getDropdownMenuActions(), - getActionViewItem: () => undefined, + getActionItem: () => undefined, onHide: () => { this.anchorElement.blur(); } @@ -479,7 +479,7 @@ export class SettingsTargetsWidget extends Widget { private userLocalSettings: Action; private userRemoteSettings: Action; private workspaceSettings: Action; - private folderSettings: FolderSettingsActionViewItem; + private folderSettings: FolderSettingsActionItem; private options: ISettingsTargetsWidgetOptions; private _settingsTarget: SettingsTarget; @@ -508,7 +508,7 @@ export class SettingsTargetsWidget extends Widget { orientation: ActionsOrientation.HORIZONTAL, ariaLabel: localize('settingsSwitcherBarAriaLabel', "Settings Switcher"), animated: false, - actionViewItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined + actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined })); this.userLocalSettings = new Action('userSettings', localize('userSettings', "User"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL)); @@ -525,7 +525,7 @@ export class SettingsTargetsWidget extends Widget { this.workspaceSettings.tooltip = this.workspaceSettings.label; const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri)); - this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionViewItem, folderSettingsAction); + this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction); this.update(); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index 08e0ab9029..8622fc8563 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -405,10 +405,10 @@ export function settingKeyToDisplayFormat(key: string, groupId = ''): { category function wordifyKey(key: string): string { return key - .replace(/\.([a-z0-9])/g, (match, p1) => ` › ${p1.toUpperCase()}`) // Replace dot with spaced '>' - .replace(/([a-z0-9])([A-Z])/g, '$1 $2') // Camel case to spacing, fooBar => foo Bar - .replace(/^[a-z]/g, match => match.toUpperCase()) // Upper casing all first letters, foo => Foo - .replace(/\b\w+\b/g, match => { // Upper casing known acronyms + .replace(/\.([a-z])/g, (match, p1) => ` › ${p1.toUpperCase()}`) + .replace(/([a-z])([A-Z])/g, '$1 $2') // fooBar => foo Bar + .replace(/^[a-z]/g, match => match.toUpperCase()) // foo => Foo + .replace(/\b\w+\b/g, match => { return knownAcronyms.has(match.toLowerCase()) ? match.toUpperCase() : match; diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts index 36dbbbd540..8fa236cd41 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts @@ -13,7 +13,7 @@ import * as nls from 'vs/nls'; import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/common/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; diff --git a/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts b/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts index 0cd8afbe9c..3f395789bb 100644 --- a/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts +++ b/src/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts @@ -101,20 +101,6 @@ suite('SettingsTree', () => { category: 'Something Else', label: 'Etc' }); - - assert.deepEqual( - settingKeyToDisplayFormat('foo.1leading.number'), - { - category: 'Foo › 1leading', - label: 'Number' - }); - - assert.deepEqual( - settingKeyToDisplayFormat('foo.1Leading.number'), - { - category: 'Foo › 1 Leading', - label: 'Number' - }); }); test('parseQuery', () => { diff --git a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts index c63324ed97..894c8ec196 100644 --- a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts @@ -192,7 +192,7 @@ class CommandPaletteEditorAction extends EditorAction { id: ShowAllCommandsAction.ID, label: nls.localize('showCommands.label', "Command Palette..."), alias: 'Command Palette', - precondition: undefined, + precondition: null, menuOpts: { group: 'z_commands', order: 1 diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts index 898ed401c3..9a7f61760c 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts @@ -139,8 +139,8 @@ class GotoLineEntry extends EditorQuickOpenEntry { return this.runPreview(); } - getInput(): IEditorInput | undefined { - return this.editorService.activeEditor; + getInput(): IEditorInput | null { + return types.withUndefinedAsNull(this.editorService.activeEditor); } getOptions(pinned?: boolean): ITextEditorOptions { diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts index 32b3d0a388..0a8ec572c0 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts @@ -288,8 +288,8 @@ class SymbolEntry extends EditorQuickOpenEntryGroup { return this.range; } - getInput(): IEditorInput | undefined { - return this.editorService.activeEditor; + getInput(): IEditorInput | null { + return types.withUndefinedAsNull(this.editorService.activeEditor); } getOptions(pinned?: boolean): ITextEditorOptions { diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index d73fa11bf0..efe92d0eba 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -35,11 +35,11 @@ import { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekV import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions'; import { Action, IAction, ActionRunner } from 'vs/base/common/actions'; -import { IActionBarOptions, ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionBarOptions, ActionsOrientation, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { basename } from 'vs/base/common/resources'; import { MenuId, IMenuService, IMenu, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; -import { fillInActionBarActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { MenuItemActionItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IChange, IEditorModel, ScrollType, IEditorContribution, IDiffEditorModel } from 'vs/editor/common/editorCommon'; import { OverviewRulerLane, ITextModel, IModelDecorationOptions } from 'vs/editor/common/model'; import { sortedDiff, firstIndex } from 'vs/base/common/arrays'; @@ -50,6 +50,21 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { INotificationService } from 'vs/platform/notification/common/notification'; import { createStyleSheet } from 'vs/base/browser/dom'; +// TODO@Joao +// Need to subclass MenuItemActionItem in order to respect +// the action context coming from any action bar, without breaking +// existing users +class DiffMenuItemActionItem extends MenuItemActionItem { + + onClick(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + + this.actionRunner.run(this._commandAction, this._context) + .then(undefined, err => this._notificationService.error(err)); + } +} + class DiffActionRunner extends ActionRunner { runAction(action: IAction, context: any): Promise { @@ -274,17 +289,17 @@ class DirtyDiffWidget extends PeekViewWidget { return { actionRunner, - actionViewItemProvider: action => this.getActionViewItem(action), + actionItemProvider: action => this.getActionItem(action), orientation: ActionsOrientation.HORIZONTAL_REVERSE }; } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (!(action instanceof MenuItemAction)) { return undefined; } - return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + return new DiffMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } protected _fillBody(container: HTMLElement): void { @@ -367,7 +382,7 @@ export class ShowPreviousChangeAction extends EditorAction { id: 'editor.action.dirtydiff.previous', label: nls.localize('show previous change', "Show Previous Change"), alias: 'Show Previous Change', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F3, weight: KeybindingWeight.EditorContrib } }); } @@ -401,7 +416,7 @@ export class ShowNextChangeAction extends EditorAction { id: 'editor.action.dirtydiff.next', label: nls.localize('show next change', "Show Next Change"), alias: 'Show Next Change', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F3, weight: KeybindingWeight.EditorContrib } }); } @@ -454,7 +469,7 @@ export class MoveToPreviousChangeAction extends EditorAction { id: 'workbench.action.editor.previousChange', label: nls.localize('move to previous change', "Move to Previous Change"), alias: 'Move to Previous Change', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F5, weight: KeybindingWeight.EditorContrib } }); } @@ -496,7 +511,7 @@ export class MoveToNextChangeAction extends EditorAction { id: 'workbench.action.editor.nextChange', label: nls.localize('move to next change', "Move to Next Change"), alias: 'Move to Next Change', - precondition: undefined, + precondition: null, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F5, weight: KeybindingWeight.EditorContrib } }); } diff --git a/src/vs/workbench/contrib/scm/browser/scmMenus.ts b/src/vs/workbench/contrib/scm/browser/scmMenus.ts index 27d4fe71cb..38a7358d85 100644 --- a/src/vs/workbench/contrib/scm/browser/scmMenus.ts +++ b/src/vs/workbench/contrib/scm/browser/scmMenus.ts @@ -9,7 +9,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { IAction } from 'vs/base/common/actions'; -import { fillInContextMenuActions, fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/contrib/scm/common/scm'; import { isSCMResource } from './scmUtil'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 83199b384f..e8c3f58fd5 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -24,10 +24,10 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { MenuItemAction, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; -import { IAction, Action, IActionViewItem, ActionRunner } from 'vs/base/common/actions'; -import { fillInContextMenuActions, ContextAwareMenuEntryActionViewItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IAction, Action, IActionItem, ActionRunner } from 'vs/base/common/actions'; +import { fillInContextMenuActions, ContextAwareMenuItemActionItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { SCMMenus } from './scmMenus'; -import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; import { isSCMResource } from './scmUtil'; import { attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; @@ -94,7 +94,7 @@ class StatusBarAction extends Action { } } -class StatusBarActionViewItem extends ActionViewItem { +class StatusBarActionItem extends ActionItem { constructor(action: StatusBarAction) { super(null, action, {}); @@ -160,7 +160,7 @@ class ProviderRenderer implements IListRenderer new StatusBarActionViewItem(a as StatusBarAction) }); + const actionBar = new ActionBar(provider, { actionItemProvider: a => new StatusBarActionItem(a as StatusBarAction) }); const disposable = Disposable.None; const templateDisposable = combinedDisposable([actionBar, badgeStyler]); @@ -366,7 +366,7 @@ class ResourceGroupRenderer implements IListRenderer constructor( private labels: ResourceLabels, - private actionViewItemProvider: IActionViewItemProvider, + private actionItemProvider: IActionItemProvider, private getSelectedResources: () => ISCMResource[], private themeService: IThemeService, private menus: SCMMenus @@ -466,7 +466,7 @@ class ResourceRenderer implements IListRenderer const fileLabel = this.labels.create(name); const actionsContainer = append(fileLabel.element, $('.actions')); const actionBar = new ActionBar(actionsContainer, { - actionViewItemProvider: this.actionViewItemProvider, + actionItemProvider: this.actionItemProvider, actionRunner: new MultipleSelectionActionRunner(this.getSelectedResources) }); @@ -827,14 +827,14 @@ export class RepositoryPanel extends ViewletPanel { const delegate = new ProviderListDelegate(); - const actionViewItemProvider = (action: IAction) => this.getActionViewItem(action); + const actionItemProvider = (action: IAction) => this.getActionItem(action); this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); this.disposables.push(this.listLabels); const renderers = [ - new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus), - new ResourceRenderer(this.listLabels, actionViewItemProvider, () => this.getSelectedResources(), this.themeService, this.menus) + new ResourceGroupRenderer(actionItemProvider, this.themeService, this.menus), + new ResourceRenderer(this.listLabels, actionItemProvider, () => this.getSelectedResources(), this.themeService, this.menus) ]; this.list = this.instantiationService.createInstance(WorkbenchList, this.listContainer, delegate, renderers, { @@ -918,12 +918,12 @@ export class RepositoryPanel extends ViewletPanel { return this.menus.getTitleSecondaryActions(); } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (!(action instanceof MenuItemAction)) { return undefined; } - return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } getActionsContext(): any { @@ -1227,12 +1227,12 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { } } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionItem(action: IAction): IActionItem | undefined { if (!(action instanceof MenuItemAction)) { return undefined; } - return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } getActions(): IAction[] { diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index 23938578e6..b2a72ec840 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -203,7 +203,7 @@ export class OpenFileHandler extends QuickOpenHandler { const queryOptions: IFileQueryBuilderOptions = { _reason: 'openFileHandler', extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService), - filePattern: query.original, + filePattern: query.value, cacheKey }; diff --git a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts index 805d0b3b07..6e64bd2275 100644 --- a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts @@ -25,6 +25,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Schemas } from 'vs/base/common/network'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { withUndefinedAsNull } from 'vs/base/common/types'; class SymbolEntry extends EditorQuickOpenEntry { private bearingResolve: Promise; @@ -48,7 +49,7 @@ class SymbolEntry extends EditorQuickOpenEntry { return nls.localize('entryAriaLabel', "{0}, symbols picker", this.getLabel()); } - getDescription(): string | undefined { + getDescription(): string | null { const containerName = this.bearing.containerName; if (this.bearing.location.uri) { if (containerName) { @@ -58,7 +59,7 @@ class SymbolEntry extends EditorQuickOpenEntry { return this.labelService.getUriLabel(this.bearing.location.uri, { relative: true }); } - return containerName; + return withUndefinedAsNull(containerName); } getIcon(): string { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 0c9782d51c..c82152c377 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -23,7 +23,7 @@ import 'vs/css!./media/searchview'; import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import * as nls from 'vs/nls'; -import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -682,7 +682,11 @@ export class SearchView extends ViewletPanel { })); } - private onContextMenu(e: ITreeContextMenuEvent): void { + private onContextMenu(e: ITreeContextMenuEvent): void { + if (!e.element) { + return; + } + if (!this.contextMenu) { this.contextMenu = this._register(this.menuService.createMenu(MenuId.SearchContext, this.contextKeyService)); } @@ -1323,6 +1327,8 @@ export class SearchView extends ViewletPanel { // Indicate as status to ARIA aria.status(message); + dom.hide(this.resultsElement); + const messageEl = this.clearMessage(); const p = dom.append(messageEl, $('p', undefined, message)); @@ -1357,7 +1363,6 @@ export class SearchView extends ViewletPanel { if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { this.showSearchWithoutFolderMessage(); } - this.reLayout(); } else { this.viewModel.searchResult.toggleHighlights(this.isVisible()); // show highlights diff --git a/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts index 6ad5d797ee..e7dca4560f 100644 --- a/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts @@ -7,8 +7,10 @@ import * as nls from 'vs/nls'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { join, basename, extname } from 'vs/base/common/path'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { join, basename, dirname, extname } from 'vs/base/common/path'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { timeout } from 'vs/base/common/async'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; @@ -17,9 +19,8 @@ import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/ import { SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { isValidBasename } from 'vs/base/common/extpath'; -import { joinPath } from 'vs/base/common/resources'; const id = 'workbench.action.openSnippets'; @@ -120,38 +121,23 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir return { existing, future }; } -async function createSnippetFile(scope: string, defaultPath: URI, quickInputService: IQuickInputService, fileService: IFileService, textFileService: ITextFileService, opener: IOpenerService) { - - function createSnippetUri(input: string) { - const filename = extname(input) !== '.code-snippets' - ? `${input}.code-snippets` - : input; - return joinPath(defaultPath, filename); - } +async function createSnippetFile(scope: string, defaultPath: URI, windowService: IWindowService, notificationService: INotificationService, fileService: IFileService, textFileService: ITextFileService, opener: IOpenerService) { await fileService.createFolder(defaultPath); + await timeout(100); // ensure quick pick closes... - const input = await quickInputService.input({ - placeHolder: nls.localize('name', "Type snippet file name"), - async validateInput(input) { - if (!input) { - return nls.localize('bad_name1', "Invalid file name"); - } - if (!isValidBasename(input)) { - return nls.localize('bad_name2', "'{0}' is not a valid file name", input); - } - if (await fileService.exists(createSnippetUri(input))) { - return nls.localize('bad_name3', "'{0}' already exists", input); - } - return undefined; - } + const path = await windowService.showSaveDialog({ + defaultPath: defaultPath.fsPath, + filters: [{ name: 'Code Snippets', extensions: ['code-snippets'] }] }); - - if (!input) { + if (!path) { + return undefined; + } + const resource = URI.file(path); + if (dirname(resource.fsPath) !== defaultPath.fsPath) { + notificationService.error(nls.localize('badPath', "Snippets must be inside this folder: '{0}'. ", defaultPath.fsPath)); return undefined; } - - const resource = createSnippetUri(input); await textFileService.write(resource, [ '{', @@ -207,8 +193,10 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise => { const snippetService = accessor.get(ISnippetsService); const quickInputService = accessor.get(IQuickInputService); const opener = accessor.get(IOpenerService); + const windowService = accessor.get(IWindowService); const modeService = accessor.get(IModeService); const envService = accessor.get(IEnvironmentService); + const notificationService = accessor.get(INotificationService); const workspaceService = accessor.get(IWorkspaceContextService); const fileService = accessor.get(IFileService); const textFileService = accessor.get(ITextFileService); @@ -245,9 +233,9 @@ CommandsRegistry.registerCommand(id, async (accessor): Promise => { }); if (globalSnippetPicks.indexOf(pick as SnippetPick) >= 0) { - return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, quickInputService, fileService, textFileService, opener); + return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, windowService, notificationService, fileService, textFileService, opener); } else if (workspaceSnippetPicks.indexOf(pick as SnippetPick) >= 0) { - return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, quickInputService, fileService, textFileService, opener); + return createSnippetFile((pick as SnippetPick).scope, (pick as SnippetPick).uri, windowService, notificationService, fileService, textFileService, opener); } else if (ISnippetPick.is(pick)) { if (pick.hint) { await createLanguageSnippetFile(pick, fileService, textFileService); diff --git a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts index 0b7d44d819..19037be242 100644 --- a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts @@ -28,13 +28,13 @@ export class TaskEntry extends Model.QuickOpenEntry { return this.task._label; } - public getDescription(): string | undefined { + public getDescription(): string | null { if (!this.taskService.needsFolderQualification()) { - return undefined; + return null; } let workspaceFolder = this.task.getWorkspaceFolder(); if (!workspaceFolder) { - return undefined; + return null; } return `${workspaceFolder.name}`; } diff --git a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts index a52b738698..5256ae1698 100644 --- a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts +++ b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts @@ -265,7 +265,7 @@ abstract class AbstractLineMatcher implements ILineMatcher { if (trim) { value = Strings.trim(value)!; } - (data as any)[property] += endOfLine + value; + data[property] += endOfLine + value; } } @@ -277,7 +277,7 @@ abstract class AbstractLineMatcher implements ILineMatcher { if (trim) { value = Strings.trim(value)!; } - (data as any)[property] = value; + data[property] = value; } } } @@ -894,9 +894,9 @@ export class ProblemPatternParser extends Parser { } function copyProperty(result: ProblemPattern, source: Config.ProblemPattern, resultKey: keyof ProblemPattern, sourceKey: keyof Config.ProblemPattern) { - const value = source[sourceKey]; + let value = source[sourceKey]; if (typeof value === 'number') { - (result as any)[resultKey] = value; + result[resultKey] = value; } } copyProperty(result, value, 'file', 'file'); diff --git a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts index a7e2240ac7..94b017b473 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts @@ -1360,6 +1360,7 @@ class TaskService extends Disposable implements ITaskService { this.modelService, this.configurationResolverService, this.telemetryService, this.contextService, this._environmentService, TaskService.OutputChannelId, + this.configurationService, (workspaceFolder: IWorkspaceFolder) => { if (!workspaceFolder) { return undefined; @@ -1973,7 +1974,7 @@ class TaskService extends Disposable implements ITaskService { } private showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise { - let _createEntries = (): Promise[]> => { + let _createEntries = (): Promise => { if (Array.isArray(tasks)) { return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); } else { @@ -1983,8 +1984,8 @@ class TaskService extends Disposable implements ITaskService { return this.quickInputService.pick(_createEntries().then((entries) => { if ((entries.length === 0) && defaultEntry) { entries.push(defaultEntry); - } else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) { - entries.push({ type: 'separator', label: '' }); + } + else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) { entries.push(additionalEntries[0]); } return entries; @@ -2012,7 +2013,7 @@ class TaskService extends Disposable implements ITaskService { Severity.Info, nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: {0}', this.ignoredWorkspaceFolders.map(f => f.name).join(', ')), [{ - label: nls.localize('TaskService.notAgain', "Don't Show Again"), + label: nls.localize('TaskService.notAgain', 'Don\'t Show Again'), isSecondary: true, run: () => { this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE); @@ -2218,7 +2219,7 @@ class TaskService extends Disposable implements ITaskService { } let runQuickPick = (promise?: Promise) => { this.showQuickPick(promise || this.getActiveTasks(), - nls.localize('TaskService.taskToTerminate', 'Select a task to terminate'), + nls.localize('TaskService.taskToTerminate', 'Select task to terminate'), { label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'), task: undefined @@ -2226,7 +2227,7 @@ class TaskService extends Disposable implements ITaskService { false, true, undefined, [{ - label: nls.localize('TaskService.terminateAllRunningTasks', 'All Running Tasks'), + label: nls.localize('TaskService.terminateAllRunningTasks', 'All running tasks'), id: 'terminateAll', task: undefined }] diff --git a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts index 9d10fe2681..6386e7fcf8 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts @@ -44,6 +44,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { Schemas } from 'vs/base/common/network'; import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/terminal'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; interface TerminalData { terminal: ITerminalInstance; @@ -171,6 +172,7 @@ export class TerminalTaskSystem implements ITaskSystem { private contextService: IWorkspaceContextService, private environmentService: IWorkbenchEnvironmentService, private outputChannelId: string, + private readonly configurationService: IConfigurationService, taskSystemInfoResolver: TaskSystemInfoResovler, ) { @@ -754,7 +756,7 @@ export class TerminalTaskSystem implements ITaskSystem { let originalCommand = task.command.name; if (isShellCommand) { shellLaunchConfig = { name: terminalName, executable: undefined, args: undefined, waitOnExit }; - this.terminalService.configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, this.terminalService.getDefaultShell(platform), platform); + this.terminalService.configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, platform); let shellSpecified: boolean = false; let shellOptions: ShellConfiguration | undefined = task.command.options && task.command.options.shell; if (shellOptions) { @@ -877,6 +879,9 @@ export class TerminalTaskSystem implements ITaskSystem { if (options.env) { shellLaunchConfig.env = options.env; } + + // Conpty doesn't do linefeeds in an expected way. Force winpty unless the user has requested otherwise. + shellLaunchConfig.forceWinpty = !this.configurationService.getValue('tasks.terminal.windowsAllowConpty'); return shellLaunchConfig; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index e3a75356f3..690430463e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -502,7 +502,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi const sendSequenceTerminalCommand = new SendSequenceTerminalCommand({ id: SendSequenceTerminalCommand.ID, - precondition: undefined, + precondition: null, description: { description: `Send Custom Sequence To Terminal`, args: [{ diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index dd4b778bc3..c6363c8fa6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -6,7 +6,7 @@ import { Terminal as XTermTerminal } from 'vscode-xterm'; import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment } from 'vs/base/common/platform'; export const ITerminalInstanceService = createDecorator('terminalInstanceService'); @@ -17,7 +17,6 @@ export interface ITerminalInstanceService { createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper; createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager; createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess; - getDefaultShell(p: Platform): string; } export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index de07d50a3a..327f071ab5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -8,7 +8,7 @@ import { Action, IAction } from 'vs/base/common/actions'; import { EndOfLinePreference } from 'vs/editor/common/model'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; -import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { TogglePanelAction } from 'vs/workbench/browser/panel'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -726,7 +726,7 @@ export class SwitchTerminalAction extends Action { } } -export class SwitchTerminalActionViewItem extends SelectActionViewItem { +export class SwitchTerminalActionItem extends SelectActionItem { constructor( action: IAction, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts b/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts index 145e54e243..a6c3a619b8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts @@ -30,7 +30,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa constructor( private _xterm: Terminal ) { - this._xterm.onKey(e => this._onKey(e.key)); + this._xterm.on('key', key => this._onKey(key)); } public dispose(): void { @@ -48,7 +48,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa } private _onEnter(): void { - if (this._xterm.buffer.cursorX >= MINIMUM_PROMPT_LENGTH) { + if (this._xterm._core.buffer.x >= MINIMUM_PROMPT_LENGTH) { this._xterm.addMarker(0); } } @@ -175,7 +175,7 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa private _getLine(marker: IMarker | Boundary): number { // Use the _second last_ row as the last row is likely the prompt if (marker === Boundary.Bottom) { - return this._xterm.buffer.baseY + this._xterm.rows - 1; + return this._xterm._core.buffer.ybase + this._xterm.rows - 1; } if (marker === Boundary.Top) { @@ -235,10 +235,10 @@ export class TerminalCommandTracker implements ITerminalCommandTracker, IDisposa if (this._currentMarker === Boundary.Bottom) { return 0; } else if (this._currentMarker === Boundary.Top) { - return 0 - (this._xterm.buffer.baseY + this._xterm.buffer.cursorY); + return 0 - (this._xterm._core.buffer.ybase + this._xterm._core.buffer.y); } else { let offset = this._getLine(this._currentMarker); - offset -= this._xterm.buffer.baseY + this._xterm.buffer.cursorY; + offset -= this._xterm._core.buffer.ybase + this._xterm._core.buffer.y; return offset; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index 8e99da0d64..3420195aeb 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -227,9 +227,9 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { return !!isWorkspaceShellAllowed; } - public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, defaultShell: string, platformOverride: platform.Platform = platform.platform): void { + public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void { const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride === platform.Platform.Windows ? platform.OperatingSystem.Windows : (platformOverride === platform.Platform.Mac ? platform.OperatingSystem.Macintosh : platform.OperatingSystem.Linux)); - mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed, defaultShell, platformOverride); + mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed, platformOverride); } private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 3195af0e4a..19438959a3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,14 +25,14 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; -import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ISearchOptions, Terminal as XTermTerminal, IBuffer } from 'vscode-xterm'; +import { ISearchOptions, Terminal as XTermTerminal } from 'vscode-xterm'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; @@ -371,7 +371,7 @@ export class TerminalInstance implements ITerminalInstance { // it gets removed and then added back to the DOM (resetting scrollTop to 0). // Upstream issue: https://github.com/sourcelair/xterm.js/issues/291 if (this._xterm) { - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + this._xterm.emit('scroll', this._xterm._core.buffer.ydisp); } } @@ -416,17 +416,18 @@ export class TerminalInstance implements ITerminalInstance { // TODO: Guess whether to use canvas or dom better rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType, // TODO: Remove this once the setting is removed upstream - experimentalCharAtlas: 'dynamic' + experimentalCharAtlas: 'dynamic', + experimentalBufferLineImpl: 'TypedArray' }); if (this._shellLaunchConfig.initialText) { this._xterm.writeln(this._shellLaunchConfig.initialText); } - this._xterm.onLineFeed(() => this._onLineFeed()); - this._xterm.onKey(e => this._onKey(e.key, e.domEvent)); + this._xterm.on('linefeed', () => this._onLineFeed()); + this._xterm.on('key', (key, ev) => this._onKey(key, ev)); if (this._processManager) { this._processManager.onProcessData(data => this._onProcessData(data)); - this._xterm.onData(data => this._processManager!.write(data)); + this._xterm.on('data', data => this._processManager!.write(data)); // TODO: How does the cwd work on detached processes? this.processReady.then(async () => { this._linkHandler.processCwd = await this._processManager!.getInitialCwd(); @@ -438,24 +439,18 @@ export class TerminalInstance implements ITerminalInstance { return; } if (this._processManager.os === platform.OperatingSystem.Windows) { - this._xterm.setOption('windowsMode', true); - // Force line data to be sent when the cursor is moved, the main purpose for - // this is because ConPTY will often not do a line feed but instead move the - // cursor, in which case we still want to send the current line's data to tasks. - this._xterm.addCsiHandler('H', () => { - this._onCursorMove(); - return false; - }); + this._xterm.winptyCompatInit(); } this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, platform.platform, this._processManager); }); } else if (this.shellLaunchConfig.isRendererOnly) { this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, undefined, undefined); } + this._xterm.on('focus', () => this._onFocus.fire(this)); // Register listener to trigger the onInput ext API if the terminal is a renderer only if (this._shellLaunchConfig.isRendererOnly) { - this._xterm.onData(data => this._sendRendererInput(data)); + this._xterm.on('data', (data) => this._sendRendererInput(data)); } this._commandTracker = new TerminalCommandTracker(this._xterm); @@ -513,7 +508,6 @@ export class TerminalInstance implements ITerminalInstance { (this._wrapperElement).xterm = this._xterm; this._xterm.open(this._xtermElement); - this._xterm.textarea.addEventListener('focus', () => this._onFocus.fire(this)); this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { // Disable all input if the terminal is exiting if (this._isExiting) { @@ -751,8 +745,8 @@ export class TerminalInstance implements ITerminalInstance { } } if (this._xterm) { - const buffer = this._xterm.buffer; - this._sendLineData(buffer, buffer.baseY + buffer.cursorY); + const buffer = (this._xterm._core.buffer); + this._sendLineData(buffer, buffer.ybase + buffer.y); this._xterm.dispose(); } @@ -865,7 +859,7 @@ export class TerminalInstance implements ITerminalInstance { // necessary if the number of rows in the terminal has decreased while it was in the // background since scrollTop changes take no effect but the terminal's position does // change since the number of visible rows decreases. - this._xterm._core._onScroll.fire(this._xterm.buffer.viewportY); + this._xterm.emit('scroll', this._xterm._core.buffer.ydisp); if (this._container && this._container.parentElement) { // Force a layout when the instance becomes invisible. This is particularly important // for ensuring that terminals that are created in the background by an extension will @@ -976,32 +970,10 @@ export class TerminalInstance implements ITerminalInstance { } this._isExiting = true; - let exitCodeMessage: string | undefined; + let exitCodeMessage: string; - // Create exit code message if (exitCode) { - if (exitCode === SHELL_PATH_INVALID_EXIT_CODE) { - exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidPath', 'The terminal shell path does not exist: {0}', this._shellLaunchConfig.executable); - } else if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) { - let args = ''; - if (typeof this._shellLaunchConfig.args === 'string') { - args = ` ${this._shellLaunchConfig.args}`; - } else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) { - args = ' ' + this._shellLaunchConfig.args.map(a => { - if (typeof a === 'string' && a.indexOf(' ') !== -1) { - return `'${a}'`; - } - return a; - }).join(' '); - } - if (this._shellLaunchConfig.executable) { - exitCodeMessage = nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode); - } else { - exitCodeMessage = nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode); - } - } else { - exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode); - } + exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode); } this._logService.debug(`Terminal process exit (id: ${this.id})${this._processManager ? ' state ' + this._processManager.processState : ''}`); @@ -1009,8 +981,8 @@ export class TerminalInstance implements ITerminalInstance { // Only trigger wait on exit when the exit was *not* triggered by the // user (via the `workbench.action.terminal.kill` command). if (this._shellLaunchConfig.waitOnExit && (!this._processManager || this._processManager.processState !== ProcessState.KILLED_BY_USER)) { - if (exitCodeMessage) { - this._xterm.writeln(exitCodeMessage); + if (exitCode) { + this._xterm.writeln(exitCodeMessage!); } if (typeof this._shellLaunchConfig.waitOnExit === 'string') { let message = this._shellLaunchConfig.waitOnExit; @@ -1025,14 +997,29 @@ export class TerminalInstance implements ITerminalInstance { } } else { this.dispose(); - if (exitCodeMessage) { + if (exitCode) { if (this._processManager && this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) { - this._notificationService.error(exitCodeMessage); + let args = ''; + if (typeof this._shellLaunchConfig.args === 'string') { + args = this._shellLaunchConfig.args; + } else if (this._shellLaunchConfig.args && this._shellLaunchConfig.args.length) { + args = ' ' + this._shellLaunchConfig.args.map(a => { + if (typeof a === 'string' && a.indexOf(' ') !== -1) { + return `'${a}'`; + } + return a; + }).join(' '); + } + if (this._shellLaunchConfig.executable) { + this._notificationService.error(nls.localize('terminal.integrated.launchFailed', 'The terminal process command \'{0}{1}\' failed to launch (exit code: {2})', this._shellLaunchConfig.executable, args, exitCode)); + } else { + this._notificationService.error(nls.localize('terminal.integrated.launchFailedExtHost', 'The terminal process failed to launch (exit code: {0})', exitCode)); + } } else { if (this._configHelper.config.showExitAlert) { - this._notificationService.error(exitCodeMessage); + this._notificationService.error(exitCodeMessage!); } else { - console.warn(exitCodeMessage); + console.warn(exitCodeMessage!); } } } @@ -1114,22 +1101,17 @@ export class TerminalInstance implements ITerminalInstance { } private _onLineFeed(): void { - const buffer = this._xterm.buffer; - const newLine = buffer.getLine(buffer.baseY + buffer.cursorY); - if (newLine && !newLine.isWrapped) { - this._sendLineData(buffer, buffer.baseY + buffer.cursorY - 1); + const buffer = (this._xterm._core.buffer); + const newLine = buffer.lines.get(buffer.ybase + buffer.y); + if (!newLine.isWrapped) { + this._sendLineData(buffer, buffer.ybase + buffer.y - 1); } } - private _onCursorMove(): void { - const buffer = this._xterm.buffer; - this._sendLineData(buffer, buffer.baseY + buffer.cursorY); - } - - private _sendLineData(buffer: IBuffer, lineIndex: number): void { - let lineData = buffer.getLine(lineIndex)!.translateToString(true); - while (lineIndex >= 0 && buffer.getLine(lineIndex--)!.isWrapped) { - lineData = buffer.getLine(lineIndex)!.translateToString(false) + lineData; + private _sendLineData(buffer: any, lineIndex: number): void { + let lineData = buffer.translateBufferLineToString(lineIndex, true); + while (lineIndex >= 0 && buffer.lines.get(lineIndex--).isWrapped) { + lineData = buffer.translateBufferLineToString(lineIndex, false) + lineData; } this._onLineData.fire(lineData); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index c65adf1a3f..ed936fbfd4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; import { Action, IAction } from 'vs/base/common/actions'; -import { IActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -16,7 +16,7 @@ import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/contrib/termin import { IThemeService, ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget'; import { editorHoverBackground, editorHoverBorder, editorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionViewItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; +import { KillTerminalAction, SwitchTerminalAction, SwitchTerminalActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction, SelectAllTerminalAction, CreateNewTerminalAction, SplitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { URI } from 'vs/base/common/uri'; @@ -161,12 +161,12 @@ export class TerminalPanel extends Panel { return this._contextMenuActions; } - public getActionViewItem(action: Action): IActionViewItem | undefined { + public getActionItem(action: Action): IActionItem | undefined { if (action.id === SwitchTerminalAction.ID) { - return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action); + return this._instantiationService.createInstance(SwitchTerminalActionItem, action); } - return super.getActionViewItem(action); + return super.getActionItem(action); } public focus(): void { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index 647b4e4a58..ae75a15120 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -169,7 +169,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { private _launchProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): ITerminalChildProcess { if (!shellLaunchConfig.executable) { - this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, this._terminalInstanceService.getDefaultShell(platform.platform)); + this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig); } const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); @@ -181,7 +181,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions(); const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables); - const useConpty = this._configHelper.config.windowsEnableConpty; + this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env); + const useConpty = (shellLaunchConfig.forceWinpty !== true) && this._configHelper.config.windowsEnableConpty; return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 60f25a591e..74e36a1f5f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -44,7 +44,7 @@ export abstract class TerminalService extends CommonTerminalService implements I super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService); } - public abstract getDefaultShell(p: platform.Platform): string; + protected abstract _getDefaultShell(p: platform.Platform): string; public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); @@ -101,7 +101,7 @@ export abstract class TerminalService extends CommonTerminalService implements I } // Never suggest if the setting is non-default already (ie. they set the setting manually) - if (this.configHelper.config.shell.windows !== this.getDefaultShell(platform.Platform.Windows)) { + if (this.configHelper.config.shell.windows !== this._getDefaultShell(platform.Platform.Windows)) { this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL); return; } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 701d3fd24b..b21f664d5a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -58,7 +58,6 @@ export const TERMINAL_CONFIG_SECTION = 'terminal.integrated'; export const DEFAULT_LETTER_SPACING = 0; export const MINIMUM_LETTER_SPACING = -5; export const DEFAULT_LINE_HEIGHT = 1; -export const SHELL_PATH_INVALID_EXIT_CODE = -1; export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; @@ -113,7 +112,7 @@ export interface ITerminalConfigHelper { /** * Merges the default shell path and args into the provided launch configuration */ - mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, defaultShell: string, platformOverride?: platform.Platform): void; + mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride?: platform.Platform): void; /** Sets whether a workspace shell configuration is allowed or not */ setWorkspaceShellAllowed(isAllowed: boolean): void; checkWorkspaceShellPermissions(osOverride?: platform.OperatingSystem): boolean; @@ -193,6 +192,12 @@ export interface IShellLaunchConfig { * provided as nothing will be inherited from the process or any configuration. */ strictEnv?: boolean; + + /** + * Moving forward, conpty will be the default. However, there are cases where conpty is not ready + * to be the default. This property will force winpty to be used, even when conpty would normally be used. + */ + forceWinpty?: boolean; } export interface ITerminalService { @@ -254,7 +259,6 @@ export interface ITerminalService { findPrevious(): void; setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; - getDefaultShell(p: platform.Platform): string; selectDefaultWindowsShell(): Promise; setWorkspaceShellAllowed(isAllowed: boolean): void; @@ -690,6 +694,7 @@ export const enum ProcessState { KILLED_BY_PROCESS } + export interface ITerminalProcessExtHostProxy extends IDisposable { readonly terminalId: number; diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index e8f62a01c2..4af692c014 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -164,14 +164,15 @@ export function mergeDefaultShellPathAndArgs( shell: IShellLaunchConfig, fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined }, isWorkspaceShellAllowed: boolean, - defaultShell: string, platformOverride: platform.Platform = platform.platform ): void { const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux'; const shellConfigValue = fetchSetting(`terminal.integrated.shell.${platformKey}`); + // const shellConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shell.${platformKey}`); const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`); + // const shellArgsConfigValue = this._workspaceConfigurationService.inspect(`terminal.integrated.shellArgs.${platformKey}`); - shell.executable = (isWorkspaceShellAllowed ? shellConfigValue.value : shellConfigValue.user) || (shellConfigValue.default || defaultShell); + shell.executable = (isWorkspaceShellAllowed ? shellConfigValue.value : shellConfigValue.user) || shellConfigValue.default; shell.args = (isWorkspaceShellAllowed ? shellArgsConfigValue.value : shellArgsConfigValue.user) || shellArgsConfigValue.default; // Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 8d661cc14d..c628e4c1f2 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -17,7 +17,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { isWindows, Platform } from 'vs/base/common/platform'; +import { isWindows } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { timeout } from 'vs/base/common/async'; @@ -106,7 +106,6 @@ export abstract class TerminalService implements ITerminalService { public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; - public abstract getDefaultShell(platform: Platform): string; public abstract selectDefaultWindowsShell(): Promise; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; @@ -427,9 +426,6 @@ export abstract class TerminalService implements ITerminalService { return Promise.resolve(null); } const current = potentialPaths.shift(); - if (current! === '') { - return this._validateShellPaths(label, potentialPaths); - } return this._fileService.exists(URI.file(current!)).then(exists => { if (!exists) { return this._validateShellPaths(label, potentialPaths); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index e746c3d018..be2c22374d 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -22,19 +22,19 @@ configurationRegistry.registerConfiguration({ type: 'object', properties: { 'terminal.integrated.shell.linux': { - markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Linux)), - type: ['string', 'null'], - default: null + markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'string', + default: getDefaultShell(platform.Platform.Linux) }, 'terminal.integrated.shell.osx': { - markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Mac)), - type: ['string', 'null'], - default: null + markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'string', + default: getDefaultShell(platform.Platform.Mac) }, 'terminal.integrated.shell.windows': { - markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Windows)), - type: ['string', 'null'], - default: null + markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'string', + default: getDefaultShell(platform.Platform.Windows) } } }); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index 953aabe361..728a676329 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -10,10 +10,9 @@ import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITermina import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; -import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment } from 'vs/base/common/platform'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; import * as typeAheadAddon from 'vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon'; -import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; let Terminal: typeof XTermTerminal; @@ -36,6 +35,7 @@ export class TerminalInstanceService implements ITerminalInstanceService { // Enable xterm.js addons Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search')); Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks')); + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/winptyCompat/winptyCompat')); Terminal.applyAddon(typeAheadAddon); // Localize strings Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line'); @@ -54,10 +54,6 @@ export class TerminalInstanceService implements ITerminalInstanceService { } public createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess { - return this._instantiationService.createInstance(TerminalProcess, shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty); + return new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty); } - - public getDefaultShell(p: Platform): string { - return getDefaultShell(p); - } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 5b934f09bc..5dc59893c9 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -98,7 +98,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - public getDefaultShell(p: platform.Platform): string { + protected _getDefaultShell(p: platform.Platform): string { return getDefaultShell(p); } @@ -117,28 +117,7 @@ export class TerminalService extends BrowserTerminalService implements ITerminal }); } - /** - * Get the executable file path of shell from registry. - * @param shellName The shell name to get the executable file path - * @returns `[]` or `[ 'path' ]` - */ - private async _getShellPathFromRegistry(shellName: string): Promise { - const Registry = await import('vscode-windows-registry'); - - try { - const shellPath = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', `SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${shellName}.exe`, ''); - - if (shellPath === undefined) { - return []; - } - - return [shellPath]; - } catch (error) { - return []; - } - } - - private async _detectWindowsShells(): Promise { + private _detectWindowsShells(): Promise { // Determine the correct System32 path. We want to point to Sysnative // when the 32-bit version of VS Code is running on a 64-bit machine. // The reason for this is because PowerShell's important PSReadline @@ -155,7 +134,6 @@ export class TerminalService extends BrowserTerminalService implements ITerminal const expectedLocations = { 'Command Prompt': [`${system32Path}\\cmd.exe`], PowerShell: [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`], - 'PowerShell Core': await this._getShellPathFromRegistry('pwsh'), 'WSL Bash': [`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`], 'Git Bash': [ `${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`, diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index b06553f064..046588baa1 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -13,12 +13,11 @@ import { getWindowsBuildNumber } from 'vs/workbench/contrib/terminal/node/termin import { IDisposable } from 'vs/base/common/lifecycle'; import { IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { exec } from 'child_process'; -import { ILogService } from 'vs/platform/log/common/log'; export class TerminalProcess implements ITerminalChildProcess, IDisposable { private _exitCode: number; private _closeTimeout: any; - private _ptyProcess: pty.IPty | undefined; + private _ptyProcess: pty.IPty; private _currentTitle: string = ''; private _processStartupComplete: Promise; private _isDisposed: boolean = false; @@ -40,8 +39,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { cols: number, rows: number, env: platform.IProcessEnvironment, - windowsEnableConpty: boolean, - @ILogService private readonly _logService: ILogService + windowsEnableConpty: boolean ) { let shellName: string; if (os.platform() === 'win32') { @@ -71,42 +69,37 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { experimentalUseConpty: useConpty }; - // TODO: Need to verify whether executable is on $PATH, otherwise things like cmd.exe will break - // fs.stat(shellLaunchConfig.executable!, (err) => { - // if (err && err.code === 'ENOENT') { - // this._exitCode = SHELL_PATH_INVALID_EXIT_CODE; - // this._queueProcessExit(); - // this._processStartupComplete = Promise.resolve(undefined); - // return; - // } - this.setupPtyProcess(shellLaunchConfig, options); - // }); - } - - private setupPtyProcess(shellLaunchConfig: IShellLaunchConfig, options: pty.IPtyForkOptions): void { - const args = shellLaunchConfig.args || []; - this._logService.trace('IPty#spawn', shellLaunchConfig.executable, args, options); - const ptyProcess = pty.spawn(shellLaunchConfig.executable!, args, options); - this._ptyProcess = ptyProcess; - this._processStartupComplete = new Promise(c => { - this.onProcessIdReady(() => c()); - }); - ptyProcess.on('data', (data) => { + try { + this._ptyProcess = pty.spawn(shellLaunchConfig.executable!, shellLaunchConfig.args || [], options); + this._processStartupComplete = new Promise(c => { + this.onProcessIdReady((pid) => { + c(); + }); + }); + } catch (error) { + // The only time this is expected to happen is when the file specified to launch with does not exist. + this._exitCode = 2; + this._queueProcessExit(); + this._processStartupComplete = Promise.resolve(undefined); + return; + } + this._ptyProcess.on('data', (data) => { this._onProcessData.fire(data); if (this._closeTimeout) { clearTimeout(this._closeTimeout); this._queueProcessExit(); } }); - ptyProcess.on('exit', (code) => { + this._ptyProcess.on('exit', (code) => { this._exitCode = code; this._queueProcessExit(); }); - this._setupTitlePolling(ptyProcess); + // TODO: We should no longer need to delay this since pty.spawn is sync setTimeout(() => { - this._sendProcessId(ptyProcess); + this._sendProcessId(); }, 500); + this._setupTitlePolling(); } public dispose(): void { @@ -121,15 +114,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { this._onProcessTitleChanged.dispose(); } - private _setupTitlePolling(ptyProcess: pty.IPty) { + private _setupTitlePolling() { // Send initial timeout async to give event listeners a chance to init setTimeout(() => { - this._sendProcessTitle(ptyProcess); + this._sendProcessTitle(); }, 0); // Setup polling this._titleInterval = setInterval(() => { - if (this._currentTitle !== ptyProcess.process) { - this._sendProcessTitle(ptyProcess); + if (this._currentTitle !== this._ptyProcess.process) { + this._sendProcessTitle(); } }, 200); } @@ -153,10 +146,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { // Attempt to kill the pty, it may have already been killed at this // point but we want to make sure try { - if (this._ptyProcess) { - this._logService.trace('IPty#kill'); - this._ptyProcess.kill(); - } + this._ptyProcess.kill(); } catch (ex) { // Swallow, the pty has already been killed } @@ -165,15 +155,15 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { }); } - private _sendProcessId(ptyProcess: pty.IPty) { - this._onProcessIdReady.fire(ptyProcess.pid); + private _sendProcessId() { + this._onProcessIdReady.fire(this._ptyProcess.pid); } - private _sendProcessTitle(ptyProcess: pty.IPty): void { + private _sendProcessTitle(): void { if (this._isDisposed) { return; } - this._currentTitle = ptyProcess.process; + this._currentTitle = this._ptyProcess.process; this._onProcessTitleChanged.fire(this._currentTitle); } @@ -186,10 +176,9 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { } public input(data: string): void { - if (this._isDisposed || !this._ptyProcess) { + if (this._isDisposed) { return; } - this._logService.trace('IPty#write', data); this._ptyProcess.write(data); } @@ -199,12 +188,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { } // Ensure that cols and rows are always >= 1, this prevents a native // exception in winpty. - if (this._ptyProcess) { - cols = Math.max(cols, 1); - rows = Math.max(rows, 1); - this._logService.trace('IPty#resize', cols, rows); - this._ptyProcess.resize(cols, rows); - } + this._ptyProcess.resize(Math.max(cols, 1), Math.max(rows, 1)); } public getInitialCwd(): Promise { @@ -214,11 +198,6 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { public getCwd(): Promise { if (platform.isMacintosh) { return new Promise(resolve => { - if (!this._ptyProcess) { - resolve(this._initialCwd); - return; - } - this._logService.trace('IPty#pid'); exec('lsof -p ' + this._ptyProcess.pid + ' | grep cwd', (error, stdout, stderr) => { if (stdout !== '') { resolve(stdout.substring(stdout.indexOf('/'), stdout.length - 1)); @@ -229,11 +208,6 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { if (platform.isLinux) { return new Promise(resolve => { - if (!this._ptyProcess) { - resolve(this._initialCwd); - return; - } - this._logService.trace('IPty#pid'); fs.readlink('/proc/' + this._ptyProcess.pid + '/cwd', (err, linkedstr) => { if (err) { resolve(this._initialCwd); diff --git a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts index 59f2815e48..28d1193c6a 100644 --- a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts +++ b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts @@ -61,15 +61,15 @@ export class WindowsShellHelper implements IWindowsShellHelper { // If this is done on every linefeed, parsing ends up taking // significantly longer due to resetting timers. Note that this is // private API. - this._xterm.onLineFeed(() => this._newLineFeed = true); - this._xterm.onCursorMove(() => { + this._xterm.on('linefeed', () => this._newLineFeed = true); + this._xterm.on('cursormove', () => { if (this._newLineFeed) { this._onCheckShell.fire(undefined); } }); // Fire a new check for the shell when any key is pressed. - this._xterm.onKey(() => this._onCheckShell.fire(undefined)); + this._xterm.on('keypress', () => this._onCheckShell.fire(undefined)); }); } diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 7552e2a32a..be331acdf3 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -238,7 +238,7 @@ class GenerateColorThemeAction extends Action { }, null, '\t'); contents = contents.replace(/\"__/g, '//"'); - return this.editorService.openEditor({ contents, mode: 'jsonc' }); + return this.editorService.openEditor({ contents, language: 'jsonc' }); } } diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index ab8897918e..cd2bea3e86 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -153,7 +153,7 @@ module.exports = function createWebviewManager(host) { scrollTarget.scrollIntoView(); } } else { - host.postMessage('did-click-link', node.href.baseVal || node.href); + host.postMessage('did-click-link', node.href); } event.preventDefault(); break; diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index 65b46d808a..16612e4235 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -170,7 +170,7 @@ export class WebviewEditorInput extends EditorInput { this._html = value; if (this._webview) { - this._webview.html = value; + this._webview.contents = value; this._currentWebviewHtml = value; } } diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index c3f0a5a9da..7c0bf67e75 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -47,7 +47,7 @@ export interface WebviewContentOptions { export interface Webview { - html: string; + contents: string; options: WebviewContentOptions; initialScrollProgress: number; state: string | undefined; diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 80419757a9..40ed73b2df 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -354,11 +354,6 @@ class WebviewKeyboardHandler extends Disposable { } } -interface WebviewContent { - readonly html: string; - readonly options: WebviewContentOptions; - readonly state: string | undefined; -} export class WebviewElement extends Disposable implements Webview { private _webview: Electron.WebviewTag; @@ -366,8 +361,8 @@ export class WebviewElement extends Disposable implements Webview { private _webviewFindWidget: WebviewFindWidget; private _findStarted: boolean = false; - private content: WebviewContent; - + private _contents: string = ''; + private _state: string | undefined = undefined; private _focused = false; private readonly _onDidFocus = this._register(new Emitter()); @@ -375,7 +370,7 @@ export class WebviewElement extends Disposable implements Webview { constructor( private readonly _options: WebviewOptions, - contentOptions: WebviewContentOptions, + private _contentOptions: WebviewContentOptions, @IInstantiationService instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, @IEnvironmentService environmentService: IEnvironmentService, @@ -385,14 +380,9 @@ export class WebviewElement extends Disposable implements Webview { @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); - this.content = { - html: '', - options: contentOptions, - state: undefined - }; - this._webview = document.createElement('webview'); this._webview.setAttribute('partition', `webview${Date.now()}`); + this._webview.setAttribute('webpreferences', 'contextIsolation=yes'); this._webview.style.flex = '0 1'; @@ -420,21 +410,21 @@ export class WebviewElement extends Disposable implements Webview { this._register(new WebviewProtocolProvider( this._webview, this._options.extension ? this._options.extension.location : undefined, - () => (this.content.options.localResourceRoots || []), + () => (this._contentOptions.localResourceRoots || []), environmentService, textFileService)); this._register(new WebviewPortMappingProvider( session, _options.extension ? _options.extension.location : undefined, - () => (this.content.options.portMappings || []), + () => (this._contentOptions.portMappings || []), tunnelService, _options.extension ? _options.extension.id : undefined, telemetryService )); if (!this._options.allowSvgs) { - const svgBlocker = this._register(new SvgBlocker(session, this.content.options)); + const svgBlocker = this._register(new SvgBlocker(session, this._contentOptions)); svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg()); } @@ -486,9 +476,8 @@ export class WebviewElement extends Disposable implements Webview { return; case 'do-update-state': - const state = event.args[0]; - this.state = state; - this._onDidUpdateState.fire(state); + this._state = event.args[0]; + this._onDidUpdateState.fire(this._state); return; case 'did-focus': @@ -553,53 +542,42 @@ export class WebviewElement extends Disposable implements Webview { this._send('initial-scroll-position', value); } - public set state(state: string | undefined) { - this.content = { - html: this.content.html, - options: this.content.options, - state, - }; + public set state(value: string | undefined) { + this._state = value; } - public set options(options: WebviewContentOptions) { - if (areWebviewInputOptionsEqual(options, this.content.options)) { + public set options(value: WebviewContentOptions) { + if (this._contentOptions && areWebviewInputOptionsEqual(value, this._contentOptions)) { return; } - this.content = { - html: this.content.html, - options: options, - state: this.content.state, - }; - this.doUpdateContent(); - } - - public set html(value: string) { - this.content = { - html: value, - options: this.content.options, - state: this.content.state, - }; - this.doUpdateContent(); - } - - public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { - if (retainContextWhenHidden && html === this.content.html && areWebviewInputOptionsEqual(options, this.content.options)) { - return; - } - this.content = { - html: html, - options: options, - state: this.content.state, - }; - this.doUpdateContent(); - } - - private doUpdateContent() { + this._contentOptions = value; this._send('content', { - contents: this.content.html, - options: this.content.options, - state: this.content.state + contents: this._contents, + options: this._contentOptions, + state: this._state + }); + } + + public set contents(value: string) { + this._contents = value; + this._send('content', { + contents: value, + options: this._contentOptions, + state: this._state + }); + } + + public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { + if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewInputOptionsEqual(options, this._contentOptions)) { + return; + } + this._contents = value; + this._contentOptions = options; + this._send('content', { + contents: this._contents, + options: this._contentOptions, + state: this._state }); } @@ -642,6 +620,7 @@ export class WebviewElement extends Disposable implements Webview { return colors; }, {} as { [key: string]: string }); + const styles = { 'vscode-font-family': '-apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif', 'vscode-font-weight': 'normal', @@ -738,7 +717,7 @@ export class WebviewElement extends Disposable implements Webview { } public reload() { - this.doUpdateContent(); + this.contents = this._contents; } public selectAll() { diff --git a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts index d8e02a8ec5..4380447820 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts @@ -80,7 +80,7 @@ export class WalkThroughInput extends EditorInput { return this.options.telemetryFrom; } - getTelemetryDescriptor(): { [key: string]: unknown } { + getTelemetryDescriptor(): object { const descriptor = super.getTelemetryDescriptor(); descriptor['target'] = this.getTelemetryFrom(); /* __GDPR__FRAGMENT__ diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index bf3d22e161..f95b5526e7 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -21,7 +21,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; +import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteFileDialogContext } from 'vs/workbench/common/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { LogStorageAction } from 'vs/platform/storage/node/storageService'; @@ -40,12 +40,12 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/electron-brow if (isMacintosh) { registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileFolderAction, OpenLocalFileFolderAction.ID, OpenLocalFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileFolderAction, OpenLocalFileFolderAction.ID, OpenLocalFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local...', fileCategory, RemoteFileDialogContext); } else { registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileAction, OpenLocalFileAction.ID, OpenLocalFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local File...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFolderAction, OpenLocalFolderAction.ID, OpenLocalFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }, RemoteFileDialogContext), 'File: Open Local Folder...', fileCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileAction, OpenLocalFileAction.ID, OpenLocalFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local File...', fileCategory, RemoteFileDialogContext); + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFolderAction, OpenLocalFolderAction.ID, OpenLocalFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }, RemoteFileDialogContext), 'File: Open Local Folder...', fileCategory, RemoteFileDialogContext); } registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 3155e8ccfe..373f1ddedb 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -26,7 +26,7 @@ import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -43,8 +43,6 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessi import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { coalesce } from 'vs/base/common/arrays'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { isEqual } from 'vs/base/common/resources'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -90,8 +88,7 @@ export class ElectronWindow extends Disposable { @IIntegrityService private readonly integrityService: IIntegrityService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @ITextFileService private readonly textFileService: ITextFileService + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService ) { super(); @@ -231,10 +228,11 @@ export class ElectronWindow extends Disposable { // Listen to editor closing (if we run with --wait) const filesToWait = this.environmentService.configuration.filesToWait; if (filesToWait) { - const waitMarkerFile = filesToWait.waitMarkerFileUri; const resourcesToWaitFor = coalesce(filesToWait.paths.map(p => p.fileUri)); + const waitMarkerFile = filesToWait.waitMarkerFileUri; + const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); - this._register(this.trackClosedWaitFiles(waitMarkerFile, resourcesToWaitFor)); + this._register(listenerDispose); } } @@ -259,6 +257,17 @@ export class ElectronWindow extends Disposable { } } + private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void { + + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { + listenerDispose.dispose(); + this.fileService.del(waitMarkerFile); + } + } + private onContextMenu(e: MouseEvent): void { if (e.target instanceof HTMLElement) { const target = e.target; @@ -479,50 +488,15 @@ export class ElectronWindow extends Disposable { // In wait mode, listen to changes to the editors and wait until the files // are closed that the user wants to wait for. When this happens we delete // the wait marker file to signal to the outside that editing is done. + const resourcesToWaitFor = request.filesToWait.paths.map(p => URI.revive(p.fileUri)); const waitMarkerFile = URI.revive(request.filesToWait.waitMarkerFileUri); - const resourcesToWaitFor = coalesce(request.filesToWait.paths.map(p => URI.revive(p.fileUri))); - this.trackClosedWaitFiles(waitMarkerFile, resourcesToWaitFor); - } - } - - private trackClosedWaitFiles(waitMarkerFile: URI, resourcesToWaitFor: URI[]): IDisposable { - const listener = this.editorService.onDidCloseEditor(async () => { - // In wait mode, listen to changes to the editors and wait until the files - // are closed that the user wants to wait for. When this happens we delete - // the wait marker file to signal to the outside that editing is done. - if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { - // If auto save is configured with the default delay (1s) it is possible - // to close the editor while the save still continues in the background. As such - // we have to also check if the files to wait for are dirty and if so wait - // for them to get saved before deleting the wait marker file. - const dirtyFilesToWait = this.textFileService.getDirty(resourcesToWaitFor); - if (dirtyFilesToWait.length > 0) { - await Promise.all(dirtyFilesToWait.map(async dirtyFileToWait => await this.joinResourceSaved(dirtyFileToWait))); - } - - listener.dispose(); - await this.fileService.del(waitMarkerFile); - } - }); - - return listener; - } - - private joinResourceSaved(resource: URI): Promise { - return new Promise(resolve => { - if (!this.textFileService.isDirty(resource)) { - return resolve(); // return early if resource is not dirty - } - - // Otherwise resolve promise when resource is saved - const listener = this.textFileService.models.onModelSaved(e => { - if (isEqual(resource, e.resource)) { - listener.dispose(); - - resolve(); + const unbind = this.editorService.onDidCloseEditor(() => { + if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { + unbind.dispose(); + this.fileService.del(waitMarkerFile); } }); - }); + } } private openResources(resources: Array, diffMode: boolean): void { diff --git a/src/vs/workbench/services/backup/common/backup.ts b/src/vs/workbench/services/backup/common/backup.ts index e9d7e45c72..f4d8cfcacb 100644 --- a/src/vs/workbench/services/backup/common/backup.ts +++ b/src/vs/workbench/services/backup/common/backup.ts @@ -9,11 +9,6 @@ import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; export const IBackupFileService = createDecorator('backupFileService'); -export interface IResolvedBackup { - value: ITextBufferFactory; - meta?: T; -} - /** * A service that handles any I/O and state associated with the backup system. */ @@ -47,10 +42,8 @@ export interface IBackupFileService { * @param resource The resource to back up. * @param content The content of the resource as snapshot. * @param versionId The version id of the resource to backup. - * @param meta The (optional) meta data of the resource to backup. This information - * can be restored later when loading the backup again. */ - backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise; + backupResource(resource: URI, content: ITextSnapshot, versionId?: number): Promise; /** * Gets a list of file backups for the current workspace. @@ -62,10 +55,10 @@ export interface IBackupFileService { /** * Resolves the backup for the given resource. * - * @param resource The resource to get the backup for. - * @return The backup file's backed up content and metadata if available. + * @param value The contents from a backup resource as stream. + * @return The backup file's backed up content as text buffer factory. */ - resolveBackupContent(resource: URI): Promise>; + resolveBackupContent(backup: URI): Promise; /** * Discards the backup associated with a resource if it exists.. diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index ef880c0dca..7acc83272e 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -3,112 +3,94 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { join } from 'vs/base/common/path'; -import { joinPath } from 'vs/base/common/resources'; -import { createHash } from 'crypto'; -import { URI } from 'vs/base/common/uri'; -import { coalesce } from 'vs/base/common/arrays'; -import { equals, deepClone } from 'vs/base/common/objects'; +import * as path from 'vs/base/common/path'; +import * as crypto from 'crypto'; +import * as pfs from 'vs/base/node/pfs'; +import { URI as Uri } from 'vs/base/common/uri'; import { ResourceQueue } from 'vs/base/common/async'; -import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IFileService } from 'vs/platform/files/common/files'; import { readToMatchingString } from 'vs/base/node/stream'; -import { ITextSnapshot } from 'vs/editor/common/model'; +import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; -import { keys, ResourceMap } from 'vs/base/common/map'; +import { keys } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { VSBuffer } from 'vs/base/common/buffer'; import { TextSnapshotReadable } from 'vs/workbench/services/textfile/common/textfiles'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export interface IBackupFilesModel { - resolve(backupRoot: URI): Promise; + resolve(backupRoot: string): Promise; - add(resource: URI, versionId?: number, meta?: object): void; - has(resource: URI, versionId?: number, meta?: object): boolean; - get(): URI[]; - remove(resource: URI): void; + add(resource: Uri, versionId?: number): void; + has(resource: Uri, versionId?: number): boolean; + get(): Uri[]; + remove(resource: Uri): void; count(): number; clear(): void; } -interface IBackupCacheEntry { - versionId?: number; - meta?: object; -} - export class BackupFilesModel implements IBackupFilesModel { - private cache: ResourceMap = new ResourceMap(); + private cache: { [resource: string]: number /* version ID */ } = Object.create(null); - constructor(private fileService: IFileService) { } + resolve(backupRoot: string): Promise { + return pfs.readDirsInDir(backupRoot).then(backupSchemas => { - async resolve(backupRoot: URI): Promise { - try { - const backupRootStat = await this.fileService.resolve(backupRoot); - if (backupRootStat.children) { - await Promise.all(backupRootStat.children - .filter(child => child.isDirectory) - .map(async backupSchema => { + // For all supported schemas + return Promise.all(backupSchemas.map(backupSchema => { - // Read backup directory for backups - const backupSchemaStat = await this.fileService.resolve(backupSchema.resource); + // Read backup directory for backups + const backupSchemaPath = path.join(backupRoot, backupSchema); + return pfs.readdir(backupSchemaPath).then(backupHashes => { - // Remember known backups in our caches - if (backupSchemaStat.children) { - backupSchemaStat.children.forEach(backupHash => this.add(backupHash.resource)); - } - })); - } - } catch (error) { - // ignore any errors - } - - return this; + // Remember known backups in our caches + backupHashes.forEach(backupHash => { + const backupResource = Uri.file(path.join(backupSchemaPath, backupHash)); + this.add(backupResource); + }); + }); + })); + }).then(() => this, error => this); } - add(resource: URI, versionId = 0, meta?: object): void { - this.cache.set(resource, { versionId, meta: deepClone(meta) }); // make sure to not store original meta in our cache... + add(resource: Uri, versionId = 0): void { + this.cache[resource.toString()] = versionId; } count(): number { - return this.cache.size; + return Object.keys(this.cache).length; } - has(resource: URI, versionId?: number, meta?: object): boolean { - const entry = this.cache.get(resource); - if (!entry) { + has(resource: Uri, versionId?: number): boolean { + const cachedVersionId = this.cache[resource.toString()]; + if (typeof cachedVersionId !== 'number') { return false; // unknown resource } - if (typeof versionId === 'number' && versionId !== entry.versionId) { - return false; // different versionId - } - - if (meta && !equals(meta, entry.meta)) { - return false; // different metadata + if (typeof versionId === 'number') { + return versionId === cachedVersionId; // if we are asked with a specific version ID, make sure to test for it } return true; } - get(): URI[] { - return this.cache.keys(); + get(): Uri[] { + return Object.keys(this.cache).map(k => Uri.parse(k)); } - remove(resource: URI): void { - this.cache.delete(resource); + remove(resource: Uri): void { + delete this.cache[resource.toString()]; } clear(): void { - this.cache.clear(); + this.cache = Object.create(null); } } export class BackupFileService implements IBackupFileService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; private impl: IBackupFileService; @@ -134,15 +116,15 @@ export class BackupFileService implements IBackupFileService { return this.impl.hasBackups(); } - loadBackupResource(resource: URI): Promise { + loadBackupResource(resource: Uri): Promise { return this.impl.loadBackupResource(resource); } - backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { - return this.impl.backupResource(resource, content, versionId, meta); + backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { + return this.impl.backupResource(resource, content, versionId); } - discardResourceBackup(resource: URI): Promise { + discardResourceBackup(resource: Uri): Promise { return this.impl.discardResourceBackup(resource); } @@ -150,28 +132,26 @@ export class BackupFileService implements IBackupFileService { return this.impl.discardAllWorkspaceBackups(); } - getWorkspaceFileBackups(): Promise { + getWorkspaceFileBackups(): Promise { return this.impl.getWorkspaceFileBackups(); } - resolveBackupContent(backup: URI): Promise> { + resolveBackupContent(backup: Uri): Promise { return this.impl.resolveBackupContent(backup); } - toBackupResource(resource: URI): URI { + toBackupResource(resource: Uri): Uri { return this.impl.toBackupResource(resource); } } class BackupFileServiceImpl implements IBackupFileService { - private static readonly PREAMBLE_END_MARKER = '\n'; - private static readonly PREAMBLE_META_SEPARATOR = ' '; // using a character that is know to be escaped in a URI as separator - private static readonly PREAMBLE_MAX_LENGTH = 10000; + private static readonly META_MARKER = '\n'; _serviceBrand: any; - private backupWorkspacePath: URI; + private backupWorkspacePath: string; private isShuttingDown: boolean; private ready: Promise; @@ -188,165 +168,115 @@ class BackupFileServiceImpl implements IBackupFileService { } initialize(backupWorkspacePath: string): void { - this.backupWorkspacePath = URI.file(backupWorkspacePath); + this.backupWorkspacePath = backupWorkspacePath; this.ready = this.init(); } private init(): Promise { - const model = new BackupFilesModel(this.fileService); + const model = new BackupFilesModel(); return model.resolve(this.backupWorkspacePath); } - async hasBackups(): Promise { - const model = await this.ready; - - return model.count() > 0; + hasBackups(): Promise { + return this.ready.then(model => { + return model.count() > 0; + }); } - async loadBackupResource(resource: URI): Promise { - const model = await this.ready; + loadBackupResource(resource: Uri): Promise { + return this.ready.then(model => { - // Return directly if we have a known backup with that resource - const backupResource = this.toBackupResource(resource); - if (model.has(backupResource)) { - return backupResource; - } + // Return directly if we have a known backup with that resource + const backupResource = this.toBackupResource(resource); + if (model.has(backupResource)) { + return backupResource; + } - return undefined; + return undefined; + }); } - async backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { if (this.isShuttingDown) { - return; + return Promise.resolve(); } - const model = await this.ready; - - const backupResource = this.toBackupResource(resource); - if (model.has(backupResource, versionId, meta)) { - return; // return early if backup version id matches requested one - } - - return this.ioOperationQueues.queueFor(backupResource).queue(async () => { - let preamble: string | undefined = undefined; - - // With Metadata: URI + META-START + Meta + END - if (meta) { - const preambleWithMeta = `${resource.toString()}${BackupFileServiceImpl.PREAMBLE_META_SEPARATOR}${JSON.stringify(meta)}${BackupFileServiceImpl.PREAMBLE_END_MARKER}`; - if (preambleWithMeta.length < BackupFileServiceImpl.PREAMBLE_MAX_LENGTH) { - preamble = preambleWithMeta; - } + return this.ready.then(model => { + const backupResource = this.toBackupResource(resource); + if (model.has(backupResource, versionId)) { + return undefined; // return early if backup version id matches requested one } - // Without Metadata: URI + END - if (!preamble) { - preamble = `${resource.toString()}${BackupFileServiceImpl.PREAMBLE_END_MARKER}`; - } + return this.ioOperationQueues.queueFor(backupResource).queue(() => { + const preamble = `${resource.toString()}${BackupFileServiceImpl.META_MARKER}`; - // Update content with value - await this.fileService.writeFile(backupResource, new TextSnapshotReadable(content, preamble)); - - // Update model - model.add(backupResource, versionId, meta); + // Update content with value + return this.fileService.writeFile(backupResource, new TextSnapshotReadable(content, preamble)).then(() => model.add(backupResource, versionId)); + }); }); } - async discardResourceBackup(resource: URI): Promise { - const model = await this.ready; - const backupResource = this.toBackupResource(resource); + discardResourceBackup(resource: Uri): Promise { + return this.ready.then(model => { + const backupResource = this.toBackupResource(resource); - return this.ioOperationQueues.queueFor(backupResource).queue(async () => { - await this.fileService.del(backupResource, { recursive: true }); - - model.remove(backupResource); + return this.ioOperationQueues.queueFor(backupResource).queue(() => { + return pfs.rimraf(backupResource.fsPath, pfs.RimRafMode.MOVE).then(() => model.remove(backupResource)); + }); }); } - async discardAllWorkspaceBackups(): Promise { + discardAllWorkspaceBackups(): Promise { this.isShuttingDown = true; - const model = await this.ready; - - await this.fileService.del(this.backupWorkspacePath, { recursive: true }); - - model.clear(); + return this.ready.then(model => { + return pfs.rimraf(this.backupWorkspacePath, pfs.RimRafMode.MOVE).then(() => model.clear()); + }); } - async getWorkspaceFileBackups(): Promise { - const model = await this.ready; + getWorkspaceFileBackups(): Promise { + return this.ready.then(model => { + const readPromises: Promise[] = []; - const backups = await Promise.all(model.get().map(async fileBackup => { - const backupPreamble = await readToMatchingString(fileBackup.fsPath, BackupFileServiceImpl.PREAMBLE_END_MARKER, BackupFileServiceImpl.PREAMBLE_MAX_LENGTH / 5, BackupFileServiceImpl.PREAMBLE_MAX_LENGTH); - if (!backupPreamble) { - return undefined; - } + model.get().forEach(fileBackup => { + readPromises.push( + readToMatchingString(fileBackup.fsPath, BackupFileServiceImpl.META_MARKER, 2000, 10000).then(Uri.parse) + ); + }); - // Preamble with metadata: URI + META-START + Meta + END - const metaStartIndex = backupPreamble.indexOf(BackupFileServiceImpl.PREAMBLE_META_SEPARATOR); - if (metaStartIndex > 0) { - return URI.parse(backupPreamble.substring(0, metaStartIndex)); - } - - // Preamble without metadata: URI + END - else { - return URI.parse(backupPreamble); - } - })); - - return coalesce(backups); + return Promise.all(readPromises); + }); } - async resolveBackupContent(backup: URI): Promise> { + resolveBackupContent(backup: Uri): Promise { + return this.fileService.readFileStream(backup).then(content => { - // Metadata extraction - let metaRaw = ''; - let metaEndFound = false; + // Add a filter method to filter out everything until the meta marker + let metaFound = false; + const metaPreambleFilter = (chunk: VSBuffer) => { + const chunkString = chunk.toString(); - // Add a filter method to filter out everything until the meta end marker - const metaPreambleFilter = (chunk: VSBuffer) => { - const chunkString = chunk.toString(); + if (!metaFound && chunk) { + const metaIndex = chunkString.indexOf(BackupFileServiceImpl.META_MARKER); + if (metaIndex === -1) { + return VSBuffer.fromString(''); // meta not yet found, return empty string + } - if (!metaEndFound) { - const metaEndIndex = chunkString.indexOf(BackupFileServiceImpl.PREAMBLE_END_MARKER); - if (metaEndIndex === -1) { - metaRaw += chunkString; - - return VSBuffer.fromString(''); // meta not yet found, return empty string + metaFound = true; + return VSBuffer.fromString(chunkString.substr(metaIndex + 1)); // meta found, return everything after } - metaEndFound = true; - metaRaw += chunkString.substring(0, metaEndIndex); // ensure to get last chunk from metadata + return chunk; + }; - return VSBuffer.fromString(chunkString.substr(metaEndIndex + 1)); // meta found, return everything after - } - - return chunk; - }; - - // Read backup into factory - const content = await this.fileService.readFileStream(backup); - const factory = await createTextBufferFactoryFromStream(content.value, metaPreambleFilter); - - // Trigger read for meta data extraction from the filter above - factory.getFirstLineText(1); - - let meta: T | undefined; - const metaStartIndex = metaRaw.indexOf(BackupFileServiceImpl.PREAMBLE_META_SEPARATOR); - if (metaStartIndex !== -1) { - try { - meta = JSON.parse(metaRaw.substr(metaStartIndex + 1)); - } catch (error) { - // ignore JSON parse errors - } - } - - return { value: factory, meta }; + return createTextBufferFactoryFromStream(content.value, metaPreambleFilter); + }); } - toBackupResource(resource: URI): URI { - return joinPath(this.backupWorkspacePath, resource.scheme, hashPath(resource)); + toBackupResource(resource: Uri): Uri { + return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, hashPath(resource))); } } @@ -360,7 +290,7 @@ export class InMemoryBackupFileService implements IBackupFileService { return Promise.resolve(this.backups.size > 0); } - loadBackupResource(resource: URI): Promise { + loadBackupResource(resource: Uri): Promise { const backupResource = this.toBackupResource(resource); if (this.backups.has(backupResource.toString())) { return Promise.resolve(backupResource); @@ -369,27 +299,27 @@ export class InMemoryBackupFileService implements IBackupFileService { return Promise.resolve(undefined); } - backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { const backupResource = this.toBackupResource(resource); this.backups.set(backupResource.toString(), content); return Promise.resolve(); } - resolveBackupContent(backupResource: URI): Promise> { + resolveBackupContent(backupResource: Uri): Promise { const snapshot = this.backups.get(backupResource.toString()); if (snapshot) { - return Promise.resolve({ value: createTextBufferFactoryFromSnapshot(snapshot) }); + return Promise.resolve(createTextBufferFactoryFromSnapshot(snapshot)); } - return Promise.reject('Unexpected backup resource to resolve'); + return Promise.resolve(undefined); } - getWorkspaceFileBackups(): Promise { - return Promise.resolve(keys(this.backups).map(key => URI.parse(key))); + getWorkspaceFileBackups(): Promise { + return Promise.resolve(keys(this.backups).map(key => Uri.parse(key))); } - discardResourceBackup(resource: URI): Promise { + discardResourceBackup(resource: Uri): Promise { this.backups.delete(this.toBackupResource(resource).toString()); return Promise.resolve(); @@ -401,17 +331,17 @@ export class InMemoryBackupFileService implements IBackupFileService { return Promise.resolve(); } - toBackupResource(resource: URI): URI { - return URI.file(join(resource.scheme, hashPath(resource))); + toBackupResource(resource: Uri): Uri { + return Uri.file(path.join(resource.scheme, hashPath(resource))); } } /* * Exported only for testing */ -export function hashPath(resource: URI): string { +export function hashPath(resource: Uri): string { const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString(); - return createHash('md5').update(str).digest('hex'); + return crypto.createHash('md5').update(str).digest('hex'); } registerSingleton(IBackupFileService, BackupFileService); \ No newline at end of file diff --git a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts new file mode 100644 index 0000000000..ef7a68b504 --- /dev/null +++ b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts @@ -0,0 +1,402 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as platform from 'vs/base/common/platform'; +import * as crypto from 'crypto'; +import * as os from 'os'; +import * as fs from 'fs'; +import * as path from 'vs/base/common/path'; +import * as pfs from 'vs/base/node/pfs'; +import { URI as Uri } from 'vs/base/common/uri'; +import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService'; +import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { DefaultEndOfLine } from 'vs/editor/common/model'; +import { Schemas } from 'vs/base/common/network'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { parseArgs } from 'vs/platform/environment/node/argv'; +import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; + +const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); +const backupHome = path.join(parentDir, 'Backups'); +const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); + +const workspaceResource = Uri.file(platform.isWindows ? 'c:\\workspace' : '/workspace'); +const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource)); +const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo'); +const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar'); +const untitledFile = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); +const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile)); +const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile)); +const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile)); + +class TestBackupEnvironmentService extends WorkbenchEnvironmentService { + + private config: IWindowConfiguration; + + constructor(workspaceBackupPath: string) { + super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + + this.config = Object.create(null); + this.config.backupPath = workspaceBackupPath; + } + + get configuration(): IWindowConfiguration { + return this.config; + } +} + +class TestBackupFileService extends BackupFileService { + constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) { + const fileService = new FileService(new NullLogService()); + fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); + const environmentService = new TestBackupEnvironmentService(workspaceBackupPath); + + super(environmentService, fileService); + } + + public toBackupResource(resource: Uri): Uri { + return super.toBackupResource(resource); + } +} + +suite('BackupFileService', () => { + let service: TestBackupFileService; + + setup(() => { + service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); + + // Delete any existing backups completely and then re-create it. + return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE).then(() => { + return pfs.mkdirp(backupHome).then(() => { + return pfs.writeFile(workspacesJsonPath, ''); + }); + }); + }); + + teardown(() => { + return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); + }); + + suite('hashPath', () => { + test('should correctly hash the path for untitled scheme URIs', () => { + const uri = Uri.from({ + scheme: 'untitled', + path: 'Untitled-1' + }); + const actual = hashPath(uri); + // If these hashes change people will lose their backed up files! + assert.equal(actual, '13264068d108c6901b3592ea654fcd57'); + assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); + }); + + test('should correctly hash the path for file scheme URIs', () => { + const uri = Uri.file('/foo'); + const actual = hashPath(uri); + // If these hashes change people will lose their backed up files! + if (platform.isWindows) { + assert.equal(actual, 'dec1a583f52468a020bd120c3f01d812'); + } else { + assert.equal(actual, '1effb2475fcfba4f9e8b8a1dbc8f3caf'); + } + assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); + }); + }); + + suite('getBackupResource', () => { + test('should get the correct backup path for text files', () => { + // Format should be: /// + const backupResource = fooFile; + const workspaceHash = hashPath(workspaceResource); + const filePathHash = hashPath(backupResource); + const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath; + assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); + }); + + test('should get the correct backup path for untitled files', () => { + // Format should be: /// + const backupResource = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); + const workspaceHash = hashPath(workspaceResource); + const filePathHash = hashPath(backupResource); + const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath; + assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); + }); + }); + + suite('loadBackupResource', () => { + test('should return whether a backup resource exists', () => { + return pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { + fs.writeFileSync(fooBackupPath, 'foo'); + service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); + return service.loadBackupResource(fooFile).then(resource => { + assert.ok(resource); + assert.equal(path.basename(resource!.fsPath), path.basename(fooBackupPath)); + return service.hasBackups().then(hasBackups => { + assert.ok(hasBackups); + }); + }); + }); + }); + }); + + suite('backupResource', () => { + test('text file', function () { + return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); + }); + }); + + test('untitled file', function () { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); + }); + }); + + test('text file (ITextSnapshot)', function () { + const model = TextModel.createFromString('test'); + + return service.backupResource(fooFile, model.createSnapshot()).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); + model.dispose(); + }); + }); + + test('untitled file (ITextSnapshot)', function () { + const model = TextModel.createFromString('test'); + + return service.backupResource(untitledFile, model.createSnapshot()).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); + model.dispose(); + }); + }); + + test('text file (large file, ITextSnapshot)', function () { + const largeString = (new Array(10 * 1024)).join('Large String\n'); + const model = TextModel.createFromString(largeString); + + return service.backupResource(fooFile, model.createSnapshot()).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\n${largeString}`); + model.dispose(); + }); + }); + + test('untitled file (large file, ITextSnapshot)', function () { + const largeString = (new Array(10 * 1024)).join('Large String\n'); + const model = TextModel.createFromString(largeString); + + return service.backupResource(untitledFile, model.createSnapshot()).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\n${largeString}`); + model.dispose(); + }); + }); + }); + + suite('discardResourceBackup', () => { + test('text file', function () { + return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + return service.discardResourceBackup(fooFile).then(() => { + assert.equal(fs.existsSync(fooBackupPath), false); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0); + }); + }); + }); + + test('untitled file', function () { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + return service.discardResourceBackup(untitledFile).then(() => { + assert.equal(fs.existsSync(untitledBackupPath), false); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0); + }); + }); + }); + }); + + suite('discardAllWorkspaceBackups', () => { + test('text file', function () { + return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2); + return service.discardAllWorkspaceBackups().then(() => { + assert.equal(fs.existsSync(fooBackupPath), false); + assert.equal(fs.existsSync(barBackupPath), false); + assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false); + }); + }); + }); + }); + + test('untitled file', function () { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + return service.discardAllWorkspaceBackups().then(() => { + assert.equal(fs.existsSync(untitledBackupPath), false); + assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false); + }); + }); + }); + + test('should disable further backups', function () { + return service.discardAllWorkspaceBackups().then(() => { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + assert.equal(fs.existsSync(workspaceBackupPath), false); + }); + }); + }); + }); + + suite('getWorkspaceFileBackups', () => { + test('("file") - text file', () => { + return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + return service.getWorkspaceFileBackups().then(textFiles => { + assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]); + return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + return service.getWorkspaceFileBackups().then(textFiles => { + assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]); + }); + }); + }); + }); + }); + + test('("file") - untitled file', () => { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + return service.getWorkspaceFileBackups().then(textFiles => { + assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]); + }); + }); + }); + + test('("untitled") - untitled file', () => { + return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + return service.getWorkspaceFileBackups().then(textFiles => { + assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']); + }); + }); + }); + }); + + test('resolveBackupContent', () => { + test('should restore the original contents (untitled file)', () => { + const contents = 'test\nand more stuff'; + service.backupResource(untitledFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => { + assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); + }); + }); + }); + + test('should restore the original contents (text file)', () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'consectetur ', + 'adipiscing ßß elit', + ].join(''); + + service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { + service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => { + assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); + }); + }); + }); + }); +}); + +suite('BackupFilesModel', () => { + test('simple', () => { + const model = new BackupFilesModel(); + + const resource1 = Uri.file('test.html'); + + assert.equal(model.has(resource1), false); + + model.add(resource1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), true); + assert.equal(model.has(resource1, 1), false); + + model.remove(resource1); + + assert.equal(model.has(resource1), false); + + model.add(resource1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), true); + assert.equal(model.has(resource1, 1), false); + + model.clear(); + + assert.equal(model.has(resource1), false); + + model.add(resource1, 1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), false); + assert.equal(model.has(resource1, 1), true); + + const resource2 = Uri.file('test1.html'); + const resource3 = Uri.file('test2.html'); + const resource4 = Uri.file('test3.html'); + + model.add(resource2); + model.add(resource3); + model.add(resource4); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource2), true); + assert.equal(model.has(resource3), true); + assert.equal(model.has(resource4), true); + }); + + test('resolve', () => { + return pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { + fs.writeFileSync(fooBackupPath, 'foo'); + + const model = new BackupFilesModel(); + + return model.resolve(workspaceBackupPath).then(model => { + assert.equal(model.has(Uri.file(fooBackupPath)), true); + }); + }); + }); + + test('get', () => { + const model = new BackupFilesModel(); + + assert.deepEqual(model.get(), []); + + const file1 = Uri.file('/root/file/foo.html'); + const file2 = Uri.file('/root/file/bar.html'); + const untitled = Uri.file('/root/untitled/bar.html'); + + model.add(file1); + model.add(file2); + model.add(untitled); + + assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]); + }); +}); diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts deleted file mode 100644 index 9785ba18bf..0000000000 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ /dev/null @@ -1,579 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import * as platform from 'vs/base/common/platform'; -import * as crypto from 'crypto'; -import * as os from 'os'; -import * as fs from 'fs'; -import * as path from 'vs/base/common/path'; -import * as pfs from 'vs/base/node/pfs'; -import { URI } from 'vs/base/common/uri'; -import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService'; -import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; -import { getRandomTestPath } from 'vs/base/test/node/testUtils'; -import { DefaultEndOfLine } from 'vs/editor/common/model'; -import { Schemas } from 'vs/base/common/network'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; -import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService } from 'vs/platform/files/common/files'; - -const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); -const backupHome = path.join(parentDir, 'Backups'); -const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); - -const workspaceResource = URI.file(platform.isWindows ? 'c:\\workspace' : '/workspace'); -const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource)); -const fooFile = URI.file(platform.isWindows ? 'c:\\Foo' : '/Foo'); -const customFile = URI.parse('customScheme://some/path'); -const customFileWithFragment = URI.parse('customScheme2://some/path#fragment'); -const barFile = URI.file(platform.isWindows ? 'c:\\Bar' : '/Bar'); -const fooBarFile = URI.file(platform.isWindows ? 'c:\\Foo Bar' : '/Foo Bar'); -const untitledFile = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); -const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile)); -const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile)); -const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile)); - -class TestBackupEnvironmentService extends WorkbenchEnvironmentService { - - private config: IWindowConfiguration; - - constructor(workspaceBackupPath: string) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); - - this.config = Object.create(null); - this.config.backupPath = workspaceBackupPath; - } - - get configuration(): IWindowConfiguration { - return this.config; - } -} - -class TestBackupFileService extends BackupFileService { - - readonly fileService: IFileService; - - constructor(workspace: URI, backupHome: string, workspacesJsonPath: string) { - const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const environmentService = new TestBackupEnvironmentService(workspaceBackupPath); - - super(environmentService, fileService); - - this.fileService = fileService; - } - - toBackupResource(resource: URI): URI { - return super.toBackupResource(resource); - } -} - -suite('BackupFileService', () => { - let service: TestBackupFileService; - - setup(async () => { - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - - // Delete any existing backups completely and then re-create it. - await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); - await pfs.mkdirp(backupHome); - - return pfs.writeFile(workspacesJsonPath, ''); - }); - - teardown(() => { - return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); - }); - - suite('hashPath', () => { - test('should correctly hash the path for untitled scheme URIs', () => { - const uri = URI.from({ - scheme: 'untitled', - path: 'Untitled-1' - }); - const actual = hashPath(uri); - // If these hashes change people will lose their backed up files! - assert.equal(actual, '13264068d108c6901b3592ea654fcd57'); - assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); - }); - - test('should correctly hash the path for file scheme URIs', () => { - const uri = URI.file('/foo'); - const actual = hashPath(uri); - // If these hashes change people will lose their backed up files! - if (platform.isWindows) { - assert.equal(actual, 'dec1a583f52468a020bd120c3f01d812'); - } else { - assert.equal(actual, '1effb2475fcfba4f9e8b8a1dbc8f3caf'); - } - assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); - }); - }); - - suite('getBackupResource', () => { - test('should get the correct backup path for text files', () => { - // Format should be: /// - const backupResource = fooFile; - const workspaceHash = hashPath(workspaceResource); - const filePathHash = hashPath(backupResource); - const expectedPath = URI.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath; - assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); - }); - - test('should get the correct backup path for untitled files', () => { - // Format should be: /// - const backupResource = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); - const workspaceHash = hashPath(workspaceResource); - const filePathHash = hashPath(backupResource); - const expectedPath = URI.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath; - assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); - }); - }); - - suite('loadBackupResource', () => { - test('should return whether a backup resource exists', async () => { - await pfs.mkdirp(path.dirname(fooBackupPath)); - fs.writeFileSync(fooBackupPath, 'foo'); - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - const resource = await service.loadBackupResource(fooFile); - assert.ok(resource); - assert.equal(path.basename(resource!.fsPath), path.basename(fooBackupPath)); - const hasBackups = await service.hasBackups(); - assert.ok(hasBackups); - }); - }); - - suite('backupResource', () => { - test('text file', async () => { - await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); - }); - - test('text file (with meta)', async () => { - await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false), undefined, { etag: '678', orphaned: true }); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath).toString(), `${fooFile.toString()} {"etag":"678","orphaned":true}\ntest`); - }); - - test('untitled file', async () => { - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); - }); - - test('text file (ITextSnapshot)', async () => { - const model = TextModel.createFromString('test'); - - await service.backupResource(fooFile, model.createSnapshot()); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); - model.dispose(); - }); - - test('untitled file (ITextSnapshot)', async () => { - const model = TextModel.createFromString('test'); - - await service.backupResource(untitledFile, model.createSnapshot()); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); - model.dispose(); - }); - - test('text file (large file, ITextSnapshot)', async () => { - const largeString = (new Array(10 * 1024)).join('Large String\n'); - const model = TextModel.createFromString(largeString); - - await service.backupResource(fooFile, model.createSnapshot()); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\n${largeString}`); - model.dispose(); - }); - - test('untitled file (large file, ITextSnapshot)', async () => { - const largeString = (new Array(10 * 1024)).join('Large String\n'); - const model = TextModel.createFromString(largeString); - - await service.backupResource(untitledFile, model.createSnapshot()); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\n${largeString}`); - model.dispose(); - }); - }); - - suite('discardResourceBackup', () => { - test('text file', async () => { - await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - await service.discardResourceBackup(fooFile); - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0); - }); - - test('untitled file', async () => { - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - await service.discardResourceBackup(untitledFile); - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0); - }); - }); - - suite('discardAllWorkspaceBackups', () => { - test('text file', async () => { - await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - await service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2); - await service.discardAllWorkspaceBackups(); - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.existsSync(barBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false); - }); - - test('untitled file', async () => { - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - await service.discardAllWorkspaceBackups(); - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false); - }); - - test('should disable further backups', async () => { - await service.discardAllWorkspaceBackups(); - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - assert.equal(fs.existsSync(workspaceBackupPath), false); - }); - }); - - suite('getWorkspaceFileBackups', () => { - test('("file") - text file', async () => { - await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - const textFiles = await service.getWorkspaceFileBackups(); - assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]); - await service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - const textFiles_1 = await service.getWorkspaceFileBackups(); - assert.deepEqual(textFiles_1.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]); - }); - - test('("file") - untitled file', async () => { - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - const textFiles = await service.getWorkspaceFileBackups(); - assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]); - }); - - test('("untitled") - untitled file', async () => { - await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); - const textFiles = await service.getWorkspaceFileBackups(); - assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']); - }); - }); - - suite('resolveBackupContent', () => { - - interface IBackupTestMetaData { - mtime?: number; - size?: number; - etag?: string; - orphaned?: boolean; - } - - test('should restore the original contents (untitled file)', async () => { - const contents = 'test\nand more stuff'; - - await testResolveBackup(untitledFile, contents); - }); - - test('should restore the original contents (untitled file with metadata)', async () => { - const contents = 'test\nand more stuff'; - - const meta = { - etag: 'the Etag', - size: 666, - mtime: Date.now(), - orphaned: true - }; - - await testResolveBackup(untitledFile, contents, meta); - }); - - test('should restore the original contents (text file)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'consectetur ', - 'adipiscing ßß elit' - ].join(''); - - await testResolveBackup(fooFile, contents); - }); - - test('should restore the original contents (text file - custom scheme)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'consectetur ', - 'adipiscing ßß elit' - ].join(''); - - await testResolveBackup(customFile, contents); - }); - - test('should restore the original contents (text file with metadata)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: 'theEtag', - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await testResolveBackup(fooFile, contents, meta); - }); - - test('should restore the original contents (text file with metadata changed once)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: 'theEtag', - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await testResolveBackup(fooFile, contents, meta); - - // Change meta and test again - meta.size = 999; - await testResolveBackup(fooFile, contents, meta); - }); - - test('should restore the original contents (text file with broken metadata)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: 'theEtag', - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false), 1, meta); - - assert.ok(await service.loadBackupResource(fooFile)); - - const fileContents = fs.readFileSync(fooBackupPath).toString(); - assert.equal(fileContents.indexOf(fooFile.toString()), 0); - - const metaIndex = fileContents.indexOf('{'); - const newFileContents = fileContents.substring(0, metaIndex) + '{{' + fileContents.substr(metaIndex); - fs.writeFileSync(fooBackupPath, newFileContents); - - const backup = await service.resolveBackupContent(service.toBackupResource(fooFile)); - assert.equal(contents, snapshotToString(backup.value.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); - assert.ok(!backup.meta); - }); - - test('should restore the original contents (text file with metadata and fragment URI)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: 'theEtag', - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await testResolveBackup(customFileWithFragment, contents, meta); - }); - - test('should restore the original contents (text file with space in name with metadata)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: 'theEtag', - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await testResolveBackup(fooBarFile, contents, meta); - }); - - test('should restore the original contents (text file with too large metadata to persist)', async () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'adipiscing ßß elit', - 'consectetur ' - ].join(''); - - const meta = { - etag: (new Array(100 * 1024)).join('Large String'), - size: 888, - mtime: Date.now(), - orphaned: false - }; - - await testResolveBackup(fooBarFile, contents, meta, null); - }); - - async function testResolveBackup(resource: URI, contents: string, meta?: IBackupTestMetaData, expectedMeta?: IBackupTestMetaData | null) { - if (typeof expectedMeta === 'undefined') { - expectedMeta = meta; - } - - await service.backupResource(resource, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false), 1, meta); - - assert.ok(await service.loadBackupResource(resource)); - - const backup = await service.resolveBackupContent(service.toBackupResource(resource)); - assert.equal(contents, snapshotToString(backup.value.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); - - if (expectedMeta) { - assert.equal(backup.meta!.etag, expectedMeta.etag); - assert.equal(backup.meta!.size, expectedMeta.size); - assert.equal(backup.meta!.mtime, expectedMeta.mtime); - assert.equal(backup.meta!.orphaned, expectedMeta.orphaned); - } else { - assert.ok(!backup.meta); - } - } - }); -}); - -suite('BackupFilesModel', () => { - - let service: TestBackupFileService; - - setup(async () => { - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - - // Delete any existing backups completely and then re-create it. - await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); - await pfs.mkdirp(backupHome); - - return pfs.writeFile(workspacesJsonPath, ''); - }); - - teardown(() => { - return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); - }); - - test('simple', () => { - const model = new BackupFilesModel(service.fileService); - - const resource1 = URI.file('test.html'); - - assert.equal(model.has(resource1), false); - - model.add(resource1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), true); - assert.equal(model.has(resource1, 1), false); - assert.equal(model.has(resource1, 1, { foo: 'bar' }), false); - - model.remove(resource1); - - assert.equal(model.has(resource1), false); - - model.add(resource1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), true); - assert.equal(model.has(resource1, 1), false); - - model.clear(); - - assert.equal(model.has(resource1), false); - - model.add(resource1, 1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), false); - assert.equal(model.has(resource1, 1), true); - - const resource2 = URI.file('test1.html'); - const resource3 = URI.file('test2.html'); - const resource4 = URI.file('test3.html'); - - model.add(resource2); - model.add(resource3); - model.add(resource4, undefined, { foo: 'bar' }); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource2), true); - assert.equal(model.has(resource3), true); - - assert.equal(model.has(resource4), true); - assert.equal(model.has(resource4, undefined, { foo: 'bar' }), true); - assert.equal(model.has(resource4, undefined, { bar: 'foo' }), false); - }); - - test('resolve', async () => { - await pfs.mkdirp(path.dirname(fooBackupPath)); - fs.writeFileSync(fooBackupPath, 'foo'); - const model = new BackupFilesModel(service.fileService); - - const resolvedModel = await model.resolve(URI.file(workspaceBackupPath)); - assert.equal(resolvedModel.has(URI.file(fooBackupPath)), true); - }); - - test('get', () => { - const model = new BackupFilesModel(service.fileService); - - assert.deepEqual(model.get(), []); - - const file1 = URI.file('/root/file/foo.html'); - const file2 = URI.file('/root/file/bar.html'); - const untitled = URI.file('/root/untitled/bar.html'); - - model.add(file1); - model.add(file2); - model.add(untitled); - - assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]); - }); -}); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 9f7ca3582f..b3d5a78aa8 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -666,7 +666,7 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati private readonly configurationCache: IConfigurationCache ) { super(); - this.key = createSHA1(join(folder.path, configFolderRelativePath)).then(key => ({ type: 'folder', key })); + this.key = createSHA1(join(folder.path, configFolderRelativePath)).then(key => ({ type: 'folder', key })); this.configurationModel = new ConfigurationModel(); } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index e60df44362..277022a9ae 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -396,7 +396,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private compareFolders(currentFolders: IWorkspaceFolder[], newFolders: IWorkspaceFolder[]): IWorkspaceFoldersChangeEvent { - const result: IWorkspaceFoldersChangeEvent = { added: [], removed: [], changed: [] }; + const result = { added: [], removed: [], changed: [] } as IWorkspaceFoldersChangeEvent; result.added = newFolders.filter(newFolder => !currentFolders.some(currentFolder => newFolder.uri.toString() === currentFolder.uri.toString())); for (let currentIndex = 0; currentIndex < currentFolders.length; currentIndex++) { let currentFolder = currentFolders[currentIndex]; diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index ef7f0fe4ea..b7ecb4f989 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -97,7 +97,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService x = elementPosition.left; y = elementPosition.top + elementPosition.height; } else { - const pos: { x: number; y: number; } = anchor; + const pos = <{ x: number; y: number; }>anchor; x = pos.x + 1; /* prevent first item from being selected automatically under mouse */ y = pos.y; } diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index e9821d1030..0a43d18e62 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -85,8 +85,8 @@ export class FileDialogService implements IFileDialogService { } private shouldUseSimplified(schema: string): boolean { - const setting = this.configurationService.getValue('files.simpleDialog.enable'); - return (schema !== Schemas.file) || (setting === true); + const setting = this.configurationService.getValue('workbench.dialogs.useSimplified'); + return (schema !== Schemas.file) || ((setting === 'true') || (setting === true)); } private ensureFileSchema(schema: string): string[] { diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index aac9b726eb..aaf81fcab6 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -22,12 +22,11 @@ import { Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings'; +import { RemoteFileDialogContext } from 'vs/workbench/common/contextkeys'; +import { equalsIgnoreCase, format } from 'vs/base/common/strings'; import { OpenLocalFileAction, OpenLocalFileFolderAction, OpenLocalFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { isValidBasename } from 'vs/base/common/extpath'; -import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; interface FileQuickPickItem extends IQuickPickItem { uri: URI; @@ -41,6 +40,11 @@ enum UpdateResult { InvalidPath } +// Reference: https://en.wikipedia.org/wiki/Filename +const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g; +const UNIX_INVALID_FILE_CHARS = /[\\/]/g; +const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; + export class RemoteFileDialog { private options: IOpenDialogOptions; private currentFolder: URI; @@ -59,7 +63,6 @@ export class RemoteFileDialog { private userHome: URI; private badPath: string | undefined; private remoteAgentEnvironment: IRemoteAgentEnvironment | null; - private separator: string; constructor( @IFileService private readonly fileService: IFileService, @@ -156,7 +159,6 @@ export class RemoteFileDialog { private async pickResource(isSave: boolean = false): Promise { this.allowFolderSelection = !!this.options.canSelectFolders; this.allowFileSelection = !!this.options.canSelectFiles; - this.separator = this.labelService.getSeparator(this.scheme, this.remoteAuthority); this.hidden = false; let homedir: URI = this.options.defaultUri ? this.options.defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri; let stat: IFileStat | undefined; @@ -278,11 +280,10 @@ export class RemoteFileDialog { // If the user has just entered more bad path, don't change anything if (!equalsIgnoreCase(value, this.constructFullUserPath()) && !this.isBadSubpath(value)) { this.filePickBox.validationMessage = undefined; - const filePickBoxUri = this.filePickBoxValue(); - const valueUri = resources.removeTrailingPathSeparator(filePickBoxUri); + const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value)); let updated: UpdateResult = UpdateResult.NotUpdated; - if (!resources.isEqual(resources.removeTrailingPathSeparator(this.currentFolder), valueUri, true)) { - updated = await this.tryUpdateItems(value, filePickBoxUri); + if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), valueUri, true)) { + updated = await this.tryUpdateItems(value, this.remoteUriFrom(this.filePickBox.value)); } if (updated === UpdateResult.NotUpdated) { this.setActiveItems(value); @@ -304,7 +305,7 @@ export class RemoteFileDialog { this.filePickBox.show(); this.contextKey.set(true); - await this.updateItems(homedir, true, this.trailing); + await this.updateItems(homedir, false, this.trailing); if (this.trailing) { this.filePickBox.valueSelection = [this.filePickBox.value.length - this.trailing.length, this.filePickBox.value.length - ext.length]; } else { @@ -330,81 +331,72 @@ export class RemoteFileDialog { return this.pathAppend(this.currentFolder, this.userEnteredPathSegment); } - private filePickBoxValue(): URI { - // The file pick box can't render everything, so we use the current folder to create the uri so that it is an existing path. - const directUri = this.remoteUriFrom(this.filePickBox.value); - const currentPath = this.pathFromUri(this.currentFolder); - if (equalsIgnoreCase(this.filePickBox.value, currentPath)) { - return this.currentFolder; - } - const currentDisplayUri = this.remoteUriFrom(currentPath); - const relativePath = resources.relativePath(currentDisplayUri, directUri); - const isSameRoot = (this.filePickBox.value.length > 1 && currentPath.length > 1) ? equalsIgnoreCase(this.filePickBox.value.substr(0, 2), currentPath.substr(0, 2)) : false; - if (relativePath && isSameRoot) { - return resources.joinPath(this.currentFolder, relativePath); - } else { - return directUri; - } - } - private async onDidAccept(): Promise { this.filePickBox.busy = true; - if (this.filePickBox.activeItems.length === 1) { - const item = this.filePickBox.selectedItems[0]; - if (item.isFolder) { - if (this.trailing) { - await this.updateItems(item.uri, true, this.trailing); - } else { - // When possible, cause the update to happen by modifying the input box. - // This allows all input box updates to happen first, and uses the same code path as the user typing. - const newPath = this.pathFromUri(item.uri); - if (startsWithIgnoreCase(newPath, this.filePickBox.value)) { - const insertValue = newPath.substring(this.filePickBox.value.length, newPath.length); - this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; - this.insertText(newPath, insertValue); - } else if ((item.label === '..') && startsWithIgnoreCase(this.filePickBox.value, newPath)) { - this.filePickBox.valueSelection = [newPath.length, this.filePickBox.value.length]; - this.insertText(newPath, ''); - } else { - await this.updateItems(item.uri, true); - } - } - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check + let resolveValue: URI | undefined; + let navigateValue: URI | undefined; + let inputUri: URI | undefined; + let inputUriDirname: URI | undefined; + let stat: IFileStat | undefined; + let statDirname: IFileStat | undefined; + try { + inputUri = resources.removeTrailingPathSeparator(this.remoteUriFrom(this.filePickBox.value)); + inputUriDirname = resources.dirname(inputUri); + statDirname = await this.fileService.resolve(inputUriDirname); + stat = await this.fileService.resolve(inputUri); + } catch (e) { + // do nothing + } + + // Find resolve value + if (this.filePickBox.activeItems.length === 0) { + if (!this.requiresTrailing && resources.isEqual(this.currentFolder, inputUri, true)) { + resolveValue = inputUri; + } else if (statDirname && statDirname.isDirectory) { + resolveValue = inputUri; + } else if (stat && stat.isDirectory) { + navigateValue = inputUri; } - } else { - // If the items have updated, don't try to resolve - if ((await this.tryUpdateItems(this.filePickBox.value, this.filePickBoxValue())) !== UpdateResult.NotUpdated) { - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check + } else if (this.filePickBox.activeItems.length === 1) { + const item = this.filePickBox.selectedItems[0]; + if (item) { + if (!item.isFolder) { + resolveValue = item.uri; + } else { + navigateValue = item.uri; + } } } - let resolveValue: URI | undefined; - // Find resolve value - if (this.filePickBox.activeItems.length === 0) { - resolveValue = this.filePickBoxValue(); - } else if (this.filePickBox.activeItems.length === 1) { - resolveValue = this.filePickBox.selectedItems[0].uri; - } - if (resolveValue) { - resolveValue = this.addPostfix(resolveValue); - } - if (await this.validate(resolveValue)) { - this.filePickBox.busy = false; - return resolveValue; + + if (navigateValue) { + // Try to navigate into the folder. + await this.updateItems(navigateValue, true, this.trailing); + } else { + if (resolveValue) { + resolveValue = this.addPostfix(resolveValue); + } + if (await this.validate(resolveValue)) { + this.filePickBox.busy = false; + return resolveValue; + } } this.filePickBox.busy = false; return undefined; } private async tryUpdateItems(value: string, valueUri: URI): Promise { - if ((value.length > 0) && ((value[value.length - 1] === '~') || (value[0] === '~'))) { + if (this.filePickBox.busy) { + this.badPath = undefined; + return UpdateResult.Updating; + } else if ((value.length > 0) && ((value[value.length - 1] === '~') || (value[0] === '~'))) { let newDir = this.userHome; if ((value[0] === '~') && (value.length > 1)) { newDir = resources.joinPath(newDir, value.substring(1)); } await this.updateItems(newDir, true); return UpdateResult.Updated; - } else if (!resources.isEqual(this.currentFolder, valueUri, true) && (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true)))) { + } else if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true))) { let stat: IFileStat | undefined; try { stat = await this.fileService.resolve(valueUri); @@ -423,7 +415,7 @@ export class RemoteFileDialog { return UpdateResult.InvalidPath; } else { const inputUriDirname = resources.dirname(valueUri); - if (!resources.isEqual(resources.removeTrailingPathSeparator(this.currentFolder), inputUriDirname, true)) { + if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), inputUriDirname, true)) { let statWithoutTrailing: IFileStat | undefined; try { statWithoutTrailing = await this.fileService.resolve(inputUriDirname); @@ -614,7 +606,7 @@ export class RemoteFileDialog { // Show a yes/no prompt const message = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri)); return this.yesNoPrompt(uri, message); - } else if (!(isValidBasename(resources.basename(uri), await this.isWindowsOS()))) { + } else if (!(await this.isValidBaseName(resources.basename(uri)))) { // Filename not allowed this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.'); return Promise.resolve(false); @@ -646,16 +638,24 @@ export class RemoteFileDialog { this.userEnteredPathSegment = trailing ? trailing : ''; this.autoCompletePathSegment = ''; const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true); - this.currentFolder = resources.addTrailingPathSeparator(newFolder, this.separator); + const oldFolder = this.currentFolder; + const newFolderPath = this.pathFromUri(newFolder, true); + this.currentFolder = this.remoteUriFrom(newFolderPath); return this.createItems(this.currentFolder).then(items => { this.filePickBox.items = items; if (this.allowFolderSelection) { this.filePickBox.activeItems = []; } - // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory. - if (!equalsIgnoreCase(this.filePickBox.value, newValue) && force) { - this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; - this.insertText(newValue, newValue); + if (!equalsIgnoreCase(this.filePickBox.value, newValue)) { + // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory. + if (!equalsIgnoreCase(this.filePickBox.value.substring(0, newValue.length), newValue)) { + this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; + this.insertText(newValue, newValue); + } else if (force || equalsIgnoreCase(this.pathFromUri(resources.dirname(oldFolder), true), newFolderPath)) { + // This is the case where the user went up one dir or is clicking on dirs. We need to make sure that we remove the final dir. + this.filePickBox.valueSelection = [newFolderPath.length, this.filePickBox.value.length]; + this.insertText(newValue, ''); + } } if (force && trailing) { // Keep the cursor position in front of the save as name. @@ -668,14 +668,15 @@ export class RemoteFileDialog { } private pathFromUri(uri: URI, endWithSeparator: boolean = false): string { - let result: string = uri.fsPath.replace(/\n/g, ''); - if (this.separator === '/') { - result = result.replace(/\\/g, this.separator); + const sep = this.labelService.getSeparator(uri.scheme, uri.authority); + let result: string; + if (sep === '/') { + result = uri.fsPath.replace(/\\/g, sep); } else { - result = result.replace(/\//g, this.separator); + result = uri.fsPath.replace(/\//g, sep); } if (endWithSeparator && !this.endsWithSlash(result)) { - result = result + this.separator; + result = result + sep; } return result; } @@ -683,7 +684,7 @@ export class RemoteFileDialog { private pathAppend(uri: URI, additional: string): string { if ((additional === '..') || (additional === '.')) { const basePath = this.pathFromUri(uri); - return basePath + (this.endsWithSlash(basePath) ? '' : this.separator) + additional; + return basePath + (this.endsWithSlash(basePath) ? '' : this.labelService.getSeparator(uri.scheme, uri.authority)) + additional; } else { return this.pathFromUri(resources.joinPath(uri, additional)); } @@ -698,6 +699,37 @@ export class RemoteFileDialog { return isWindowsOS; } + private async isValidBaseName(name: string): Promise { + if (!name || name.length === 0 || /^\s+$/.test(name)) { + return false; // require a name that is not just whitespace + } + + const isWindowsOS = await this.isWindowsOS(); + const INVALID_FILE_CHARS = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS; + INVALID_FILE_CHARS.lastIndex = 0; // the holy grail of software development + if (INVALID_FILE_CHARS.test(name)) { + return false; // check for certain invalid file characters + } + + if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { + return false; // check for certain invalid file names + } + + if (name === '.' || name === '..') { + return false; // check for reserved values + } + + if (isWindowsOS && name[name.length - 1] === '.') { + return false; // Windows: file cannot end with a "." + } + + if (isWindowsOS && name.length !== name.trim().length) { + return false; // Windows: file cannot end with a whitespace + } + + return true; + } + private endsWithSlash(s: string) { return /[\/\\]$/.test(s); } @@ -711,7 +743,7 @@ export class RemoteFileDialog { private createBackItem(currFolder: URI): FileQuickPickItem | null { const parentFolder = resources.dirname(currFolder)!; if (!resources.isEqual(currFolder, parentFolder, true)) { - return { label: '..', uri: resources.addTrailingPathSeparator(parentFolder, this.separator), isFolder: true }; + return { label: '..', uri: resources.dirname(currFolder), isFolder: true }; } return null; } @@ -769,7 +801,6 @@ export class RemoteFileDialog { const stat = await this.fileService.resolve(fullPath); if (stat.isDirectory) { filename = this.basenameWithTrailingSlash(fullPath); - fullPath = resources.addTrailingPathSeparator(fullPath, this.separator); return { label: filename, uri: fullPath, isFolder: true, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined, FileKind.FOLDER) }; } else if (!stat.isDirectory && this.allowFileSelection && this.filterFile(fullPath)) { return { label: filename, uri: fullPath, isFolder: false, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined) }; diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index bac156956e..58162b8e58 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -532,7 +532,9 @@ export class EditorService extends Disposable implements EditorServiceImpl { const untitledInput = input; if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) { // {{SQL CARBON EDIT}} - return convertEditorInput(this.untitledEditorService.createOrGet(untitledInput.resource, untitledInput.mode, untitledInput.contents, untitledInput.encoding), undefined, this.instantiationService); + + let modeId: string = untitledInput.language ? untitledInput.language : getFileMode(this.instantiationService, untitledInput.resource); + return convertEditorInput(this.untitledEditorService.createOrGet(untitledInput.resource, modeId, untitledInput.contents, untitledInput.encoding), undefined, this.instantiationService); } // Resource Editor Support @@ -544,14 +546,14 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // {{SQL CARBON EDIT}} - return convertEditorInput(this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.mode, resourceInput.forceFile) as EditorInput, + return convertEditorInput(this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.forceFile) as EditorInput, undefined, this.instantiationService); } throw new Error('Unknown input type'); } - private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string | undefined, description: string | undefined, encoding: string | undefined, mode: string | undefined, forceFile: boolean | undefined): ICachedEditorInput { + private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string | undefined, description: string | undefined, encoding: string | undefined, forceFile: boolean | undefined): ICachedEditorInput { if (EditorService.CACHE.has(resource)) { const input = EditorService.CACHE.get(resource)!; if (input instanceof ResourceEditorInput) { @@ -562,18 +564,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { if (description) { input.setDescription(description); } - - if (mode) { - input.setPreferredMode(mode); - } } else if (!(input instanceof DataUriEditorInput)) { if (encoding) { input.setPreferredEncoding(encoding); } - - if (mode) { - input.setPreferredMode(mode); - } } return input; @@ -583,7 +577,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { // File if (forceFile /* fix for https://github.com/Microsoft/vscode/issues/48275 */ || this.fileService.canHandleResource(resource)) { - input = this.fileInputFactory.createFileInput(resource, encoding, mode, instantiationService); + input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); } // Data URI @@ -593,12 +587,13 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Resource else { - input = instantiationService.createInstance(ResourceEditorInput, label, description, resource, mode); + input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); } - // Add to cache and remove when input gets disposed EditorService.CACHE.set(resource, input); - Event.once(input.onDispose)(() => EditorService.CACHE.delete(resource)); + Event.once(input.onDispose)(() => { + EditorService.CACHE.delete(resource); + }); return input; } diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 1f5fbba7c9..eec96b9f65 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -24,10 +24,10 @@ export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyFileEditorForEditorGroupService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { super.setInput(input, options, token); - await input.resolve(); + return input.resolve().then(() => undefined); } getId(): string { return 'MyFileEditorForEditorGroupService'; } @@ -45,8 +45,6 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { setEncoding(encoding: string) { } getEncoding(): string { return null!; } setPreferredEncoding(encoding: string) { } - setMode(mode: string) { } - setPreferredMode(mode: string) { } getResource(): URI { return this.resource; } setForceOpenAsBinary(): void { } } diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 987bd9c093..d112350ed7 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -29,8 +29,6 @@ import { timeout } from 'vs/base/common/async'; import { toResource } from 'vs/base/test/common/utils'; import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; -import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; // {{SQL CARBON EDIT}} - Disable editor tests /* @@ -38,10 +36,10 @@ export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyTestEditorForEditorService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { super.setInput(input, options, token); - await input.resolve(); + return input.resolve().then(() => undefined); } getId(): string { return 'MyTestEditorForEditorService'; } @@ -60,8 +58,6 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { setEncoding(encoding: string) { } getEncoding(): string { return null!; } setPreferredEncoding(encoding: string) { } - setMode(mode: string) { } - setPreferredMode(mode: string) { } getResource(): URI { return this.resource; } setForceOpenAsBinary(): void { } setFailToOpen(): void { @@ -81,7 +77,7 @@ class FileServiceProvider extends Disposable { } } -*/suite('EditorService', () => {/* +*/suite('Editor service', () => {/* function registerTestEditorInput(): void { Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), new SyncDescriptor(TestEditorInput)); @@ -89,7 +85,7 @@ class FileServiceProvider extends Disposable { registerTestEditorInput(); - test('basics', async () => { + test('basics', function () { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -118,49 +114,51 @@ class FileServiceProvider extends Disposable { didCloseEditorListenerCounter++; }); - await part.whenRestored; + return part.whenRestored.then(() => { - // Open input - let editor = await service.openEditor(input, { pinned: true }); + // Open input + return service.openEditor(input, { pinned: true }).then(editor => { + assert.ok(editor instanceof TestEditorControl); + assert.equal(editor, service.activeControl); + assert.equal(input, service.activeEditor); + assert.equal(service.visibleControls.length, 1); + assert.equal(service.visibleControls[0], editor); + assert.ok(!service.activeTextEditorWidget); + assert.equal(service.visibleTextEditorWidgets.length, 0); + assert.equal(service.isOpen(input), true); + assert.equal(service.getOpened({ resource: input.getResource() }), input); + assert.equal(service.isOpen(input, part.activeGroup), true); + assert.equal(activeEditorChangeEventCounter, 1); + assert.equal(visibleEditorChangeEventCounter, 1); - assert.ok(editor instanceof TestEditorControl); - assert.equal(editor, service.activeControl); - assert.equal(input, service.activeEditor); - assert.equal(service.visibleControls.length, 1); - assert.equal(service.visibleControls[0], editor); - assert.ok(!service.activeTextEditorWidget); - assert.equal(service.visibleTextEditorWidgets.length, 0); - assert.equal(service.isOpen(input), true); - assert.equal(service.getOpened({ resource: input.getResource() }), input); - assert.equal(service.isOpen(input, part.activeGroup), true); - assert.equal(activeEditorChangeEventCounter, 1); - assert.equal(visibleEditorChangeEventCounter, 1); + // Close input + return editor!.group!.closeEditor(input).then(() => { + assert.equal(didCloseEditorListenerCounter, 1); + assert.equal(activeEditorChangeEventCounter, 2); + assert.equal(visibleEditorChangeEventCounter, 2); + assert.ok(input.gotDisposed); - // Close input - await editor!.group!.closeEditor(input); + // Open again 2 inputs + return service.openEditor(input, { pinned: true }).then(editor => { + return service.openEditor(otherInput, { pinned: true }).then(editor => { + assert.equal(service.visibleControls.length, 1); + assert.equal(service.isOpen(input), true); + assert.equal(service.isOpen(otherInput), true); - assert.equal(didCloseEditorListenerCounter, 1); - assert.equal(activeEditorChangeEventCounter, 2); - assert.equal(visibleEditorChangeEventCounter, 2); - assert.ok(input.gotDisposed); + assert.equal(activeEditorChangeEventCounter, 4); + assert.equal(visibleEditorChangeEventCounter, 4); - // Open again 2 inputs - await service.openEditor(input, { pinned: true }); - editor = await service.openEditor(otherInput, { pinned: true }); - - assert.equal(service.visibleControls.length, 1); - assert.equal(service.isOpen(input), true); - assert.equal(service.isOpen(otherInput), true); - - assert.equal(activeEditorChangeEventCounter, 4); - assert.equal(visibleEditorChangeEventCounter, 4); - - activeEditorChangeListener.dispose(); - visibleEditorChangeListener.dispose(); - didCloseEditorListener.dispose(); + activeEditorChangeListener.dispose(); + visibleEditorChangeListener.dispose(); + didCloseEditorListener.dispose(); + }); + }); + }); + }); + }); }); - test('openEditors() / replaceEditors()', async () => { + test('openEditors() / replaceEditors()', function () { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -175,16 +173,18 @@ class FileServiceProvider extends Disposable { const otherInput = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource2-openEditors')); const replaceInput = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource3-openEditors')); - await part.whenRestored; + return part.whenRestored.then(() => { - // Open editors - await service.openEditors([{ editor: input }, { editor: otherInput }]); - assert.equal(part.activeGroup.count, 2); + // Open editors + return service.openEditors([{ editor: input }, { editor: otherInput }]).then(() => { + assert.equal(part.activeGroup.count, 2); - // Replace editors - await service.replaceEditors([{ editor: input, replacement: replaceInput }], part.activeGroup); - assert.equal(part.activeGroup.count, 2); - assert.equal(part.activeGroup.getIndexOfEditor(replaceInput), 0); + return service.replaceEditors([{ editor: input, replacement: replaceInput }], part.activeGroup).then(() => { + assert.equal(part.activeGroup.count, 2); + assert.equal(part.activeGroup.getIndexOfEditor(replaceInput), 0); + }); + }); + }); }); test('caching', function () { @@ -236,15 +236,10 @@ class FileServiceProvider extends Disposable { assert.ok(!input1AgainAndAgain!.isDisposed()); }); - test('createInput', async function () { + test('createInput', function () { const instantiationService = workbenchInstantiationService(); const service: EditorService = instantiationService.createInstance(EditorService); - const mode = 'create-input-test'; - ModesRegistry.registerLanguage({ - id: mode, - }); - // Untyped Input (file) let input = service.createInput({ resource: toResource.call(this, '/index.html'), options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof FileEditorInput); @@ -257,18 +252,6 @@ class FileServiceProvider extends Disposable { contentInput = input; assert.equal(contentInput.getPreferredEncoding(), 'utf16le'); - // Untyped Input (file, mode) - input = service.createInput({ resource: toResource.call(this, '/index.html'), mode }); - assert(input instanceof FileEditorInput); - contentInput = input; - assert.equal(contentInput.getPreferredMode(), mode); - - // Untyped Input (file, different mode) - input = service.createInput({ resource: toResource.call(this, '/index.html'), mode: 'text' }); - assert(input instanceof FileEditorInput); - contentInput = input; - assert.equal(contentInput.getPreferredMode(), 'text'); - // Untyped Input (untitled) input = service.createInput({ options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof UntitledEditorInput); @@ -276,14 +259,6 @@ class FileServiceProvider extends Disposable { // Untyped Input (untitled with contents) input = service.createInput({ contents: 'Hello Untitled', options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof UntitledEditorInput); - let model = await input.resolve() as UntitledEditorModel; - assert.equal(model.textEditorModel!.getValue(), 'Hello Untitled'); - - // Untyped Input (untitled with mode) - input = service.createInput({ mode, options: { selection: { startLineNumber: 1, startColumn: 1 } } }); - assert(input instanceof UntitledEditorInput); - model = await input.resolve() as UntitledEditorModel; - assert.equal(model.getMode(), mode); // Untyped Input (untitled with file path) input = service.createInput({ resource: URI.file('/some/path.txt'), forceUntitled: true, options: { selection: { startLineNumber: 1, startColumn: 1 } } }); @@ -303,10 +278,6 @@ class FileServiceProvider extends Disposable { assert.ok((input as UntitledEditorInput).hasAssociatedFilePath); provider.dispose(); - - // Untyped Input (resource) - input = service.createInput({ resource: URI.parse('custom:resource') }); - assert(input instanceof ResourceEditorInput); }); test('delegate', function (done) { @@ -329,7 +300,7 @@ class FileServiceProvider extends Disposable { const ed = instantiationService.createInstance(MyEditor, 'my.editor'); - const inp = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.parse('my://resource-delegate'), undefined); + const inp = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.parse('my://resource-delegate')); const delegate = instantiationService.createInstance(DelegatingEditorService); delegate.setEditorOpenHandler((group: IEditorGroup, input: IEditorInput, options?: EditorOptions) => { assert.strictEqual(input, inp); @@ -342,7 +313,7 @@ class FileServiceProvider extends Disposable { delegate.openEditor(inp); }); - test('close editor does not dispose when editor opened in other group', async () => { + test('close editor does not dispose when editor opened in other group', function () { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -358,26 +329,30 @@ class FileServiceProvider extends Disposable { const rootGroup = part.activeGroup; const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); - await part.whenRestored; + return part.whenRestored.then(() => { - // Open input - await service.openEditor(input, { pinned: true }); - await service.openEditor(input, { pinned: true }, rightGroup); + // Open input + return service.openEditor(input, { pinned: true }).then(editor => { + return service.openEditor(input, { pinned: true }, rightGroup).then(editor => { + const editors = service.editors; + assert.equal(editors.length, 2); + assert.equal(editors[0], input); + assert.equal(editors[1], input); - const editors = service.editors; - assert.equal(editors.length, 2); - assert.equal(editors[0], input); - assert.equal(editors[1], input); + // Close input + return rootGroup.closeEditor(input).then(() => { + assert.equal(input.isDisposed(), false); - // Close input - await rootGroup.closeEditor(input); - assert.equal(input.isDisposed(), false); - - await rightGroup.closeEditor(input); - assert.equal(input.isDisposed(), true); + return rightGroup.closeEditor(input).then(() => { + assert.equal(input.isDisposed(), true); + }); + }); + }); + }); + }); }); - test('open to the side', async () => { + test('open to the side', function () { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -393,20 +368,22 @@ class FileServiceProvider extends Disposable { const rootGroup = part.activeGroup; - await part.whenRestored; + return part.whenRestored.then(() => { + return service.openEditor(input1, { pinned: true }, rootGroup).then(editor => { + return service.openEditor(input1, { pinned: true, preserveFocus: true }, SIDE_GROUP).then(editor => { + assert.equal(part.activeGroup, rootGroup); + assert.equal(part.count, 2); + assert.equal(editor!.group, part.groups[1]); - await service.openEditor(input1, { pinned: true }, rootGroup); - let editor = await service.openEditor(input1, { pinned: true, preserveFocus: true }, SIDE_GROUP); - - assert.equal(part.activeGroup, rootGroup); - assert.equal(part.count, 2); - assert.equal(editor!.group, part.groups[1]); - - // Open to the side uses existing neighbour group if any - editor = await service.openEditor(input2, { pinned: true, preserveFocus: true }, SIDE_GROUP); - assert.equal(part.activeGroup, rootGroup); - assert.equal(part.count, 2); - assert.equal(editor!.group, part.groups[1]); + // Open to the side uses existing neighbour group if any + return service.openEditor(input2, { pinned: true, preserveFocus: true }, SIDE_GROUP).then(editor => { + assert.equal(part.activeGroup, rootGroup); + assert.equal(part.count, 2); + assert.equal(editor!.group, part.groups[1]); + }); + }); + }); + }); }); test('active editor change / visible editor change events', async function () { diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 90f69da182..ba73aa6bcb 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -255,7 +255,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { * This routine makes the following assumptions: * The root element is an object literal */ - private static _replaceNLStrings(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void { + private static _replaceNLStrings(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void { function processEntry(obj: any, key: string | number, command?: boolean) { let value = obj[key]; if (types.isString(value)) { diff --git a/src/vs/workbench/services/files/test/node/diskFileService.test.ts b/src/vs/workbench/services/files/test/node/diskFileService.test.ts index 328718350c..19e141d72d 100644 --- a/src/vs/workbench/services/files/test/node/diskFileService.test.ts +++ b/src/vs/workbench/services/files/test/node/diskFileService.test.ts @@ -1523,10 +1523,6 @@ suite('Disk File Service', () => { }); test('watch - file - rename file', done => { - if (isWindows) { - return done(); // watch tests are flaky on other platforms - } - const toWatch = URI.file(join(testDir, 'index-watch1.html')); const toWatchRenamed = URI.file(join(testDir, 'index-watch1-renamed.html')); writeFileSync(toWatch.fsPath, 'Init'); diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 68ba90e0a6..aec7bbf220 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -958,7 +958,7 @@ export class HistoryService extends Disposable implements IHistoryService { getLastActiveFile(filterByScheme: string): URI | undefined { const history = this.getHistory(); for (const input of history) { - let resource: URI | undefined; + let resource: URI | null; if (input instanceof EditorInput) { resource = toResource(input, { filterByScheme }); } else { diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index eeffa3f7db..21b3e6af8d 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -210,7 +210,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private resolveModelReference(): Promise> { return this.fileService.exists(this.resource) .then(exists => { - const EOL = this.configurationService.getValue<{}>('files', { overrideIdentifier: 'json' })['eol']; + const EOL = this.configurationService.getValue('files', { overrideIdentifier: 'json' })['eol']; const result: Promise = exists ? Promise.resolve(null) : this.textFileService.write(this.resource, this.getEmptyContent(EOL), { encoding: 'utf8' }); return result.then(() => this.textModelResolverService.createModelReference(this.resource)); }); diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index 74dda793dd..6b54213771 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -396,7 +396,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { const keybinding = item.keybinding; if (!keybinding) { // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); + result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); } else { const resolvedKeybindings = this.resolveKeybinding(keybinding); for (const resolvedKeybinding of resolvedKeybindings) { @@ -415,7 +415,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { const parts = item.parts; if (parts.length === 0) { // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); + result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); } else { const resolvedKeybindings = this._keyboardMapper.resolveUserBinding(parts); for (const resolvedKeybinding of resolvedKeybindings) { diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 7b50510857..a0204f6cf2 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -274,7 +274,7 @@ suite('KeybindingsEditing', () => { parts.push(aSimpleKeybinding(chordPart)); } } - const keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : undefined; + let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; return new ResolvedKeybindingItem(keybinding, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : undefined, isDefault === undefined ? true : isDefault); } diff --git a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts index 4c805f68f6..cab5d30451 100644 --- a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts +++ b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts @@ -174,7 +174,7 @@ export class KeybindingsEditorModel extends EditorModel { const commandsWithDefaultKeybindings = this.keybindingsService.getDefaultKeybindings().map(keybinding => keybinding.command); for (const command of KeybindingResolver.getAllUnboundCommands(boundCommands)) { - const keybindingItem = new ResolvedKeybindingItem(undefined, command, null, undefined, commandsWithDefaultKeybindings.indexOf(command) === -1); + const keybindingItem = new ResolvedKeybindingItem(null, command, null, undefined, commandsWithDefaultKeybindings.indexOf(command) === -1); this._keybindingItemsSortedByPrecedence.push(KeybindingsEditorModel.toKeybindingEntry(command, keybindingItem, workbenchActionsRegistry, editorActionsLabels)); } this._keybindingItems = this._keybindingItemsSortedByPrecedence.slice(0).sort((a, b) => KeybindingsEditorModel.compareKeybindingData(a, b)); diff --git a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts index ddd0314c10..3a02fcdac8 100644 --- a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts +++ b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts @@ -31,7 +31,7 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput { constructor(defaultSettingsResource: URI, @ITextModelService textModelResolverService: ITextModelService ) { - super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, undefined, textModelResolverService); + super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService); } getTypeId(): string { diff --git a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts index 3fcd994409..9b6e031ec7 100644 --- a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts @@ -617,7 +617,7 @@ suite('KeybindingsEditorModel test', () => { parts.push(aSimpleKeybinding(chordPart)); } } - const keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : undefined; + let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; return new ResolvedKeybindingItem(keybinding, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : undefined, isDefault === undefined ? true : isDefault); } diff --git a/src/vs/workbench/services/progress/test/progressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts index f0dc396eae..a491553d18 100644 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IAction, IActionItem } from 'vs/base/common/actions'; import { IEditorControl } from 'vs/workbench/common/editor'; import { ScopedProgressService, ScopedService } from 'vs/workbench/services/progress/browser/progressService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -51,7 +51,7 @@ class TestViewlet implements IViewlet { /** * Returns the action item for a specific action. */ - getActionViewItem(action: IAction): IActionViewItem { + getActionItem(action: IAction): IActionItem { return null!; } diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 1b80a9ac46..d678655a62 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -22,7 +22,6 @@ import { URI } from 'vs/base/common/uri'; import { readdir } from 'vs/base/node/pfs'; import { IFileQuery, IFolderQuery, IProgressMessage, ISearchEngineStats, IRawFileMatch, ISearchEngine, ISearchEngineSuccess } from 'vs/workbench/services/search/common/search'; import { spawnRipgrepCmd } from './ripgrepFileSearch'; -import { prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; interface IDirectoryEntry { base: string; @@ -77,7 +76,7 @@ export class FileWalker { this.errors = []; if (this.filePattern) { - this.normalizedFilePatternLowercase = prepareQuery(this.filePattern).lowercase; + this.normalizedFilePatternLowercase = strings.stripWildcards(this.filePattern).toLowerCase(); } this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern); diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 7fd3fb7de8..6b63bd17ae 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -16,7 +16,7 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import * as strings from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; -import { MAX_FILE_SIZE } from 'vs/base/node/pfs'; +import { MAX_FILE_SIZE } from 'vs/platform/files/node/fileConstants'; import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery, IFileSearchProgressItem, IRawFileMatch, IRawSearchService, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess } from 'vs/workbench/services/search/common/search'; import { Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch'; import { TextSearchEngineAdapter } from 'vs/workbench/services/search/node/textSearchAdapter'; @@ -312,7 +312,7 @@ export class SearchService implements IRawSearchService { // Pattern match on results const results: IRawFileMatch[] = []; - const normalizedSearchValueLowercase = prepareQuery(searchValue).value; + const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); for (const entry of cachedEntries) { // Check if this entry is a match for the search value diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 8a07bf7270..42bd2082c0 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; @@ -18,12 +18,13 @@ import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel' import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RunOnceScheduler, timeout } from 'vs/base/common/async'; import { ITextBufferFactory } from 'vs/editor/common/model'; import { hash } from 'vs/base/common/hash'; +import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { isLinux } from 'vs/base/common/platform'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -32,13 +33,6 @@ import { isEqual, isEqualOrParent, extname, basename } from 'vs/base/common/reso import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; -export interface IBackupMetaData { - mtime: number; - size: number; - etag: string; - orphaned: boolean; -} - /** * The text file editor model listens to changes to its underlying code editor model and saves these changes through the file service back to the disk. */ @@ -63,16 +57,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private resource: URI; - private contentEncoding: string; // encoding as reported from disk - private preferredEncoding: string; // encoding as chosen by the user - - private preferredMode: string; // mode as chosen by the user + private contentEncoding: string; // encoding as reported from disk + private preferredEncoding: string; // encoding as chosen by the user private versionId: number; private bufferSavedVersionId: number; private blockModelContentChange: boolean; - private lastResolvedFileStat: IFileStatWithMetadata; + private createTextEditorModelPromise: Promise | null; + + private lastResolvedDiskStat: IFileStatWithMetadata; private autoSaveAfterMillies?: number; private autoSaveAfterMilliesEnabled: boolean; @@ -94,7 +88,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil constructor( resource: URI, preferredEncoding: string, - preferredMode: string, @INotificationService private readonly notificationService: INotificationService, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @@ -111,7 +104,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.resource = resource; this.preferredEncoding = preferredEncoding; - this.preferredMode = preferredMode; this.inOrphanMode = false; this.dirty = false; this.versionId = 0; @@ -207,40 +199,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private onFilesAssociationChange(): void { - if (!this.isResolved()) { + if (!this.textEditorModel) { return; } const firstLineText = this.getFirstLineText(this.textEditorModel); - const languageSelection = this.getOrCreateMode(this.resource, this.modeService, this.preferredMode, firstLineText); + const languageSelection = this.getOrCreateMode(this.modeService, undefined, firstLineText); this.modelService.setMode(this.textEditorModel, languageSelection); } - setMode(mode: string): void { - super.setMode(mode); - - this.preferredMode = mode; - } - - async backup(target = this.resource): Promise { - if (this.isResolved()) { - - // Only fill in model metadata if resource matches - let meta: IBackupMetaData | undefined = undefined; - if (isEqual(target, this.resource) && this.lastResolvedFileStat) { - meta = { - mtime: this.lastResolvedFileStat.mtime, - size: this.lastResolvedFileStat.size, - etag: this.lastResolvedFileStat.etag, - orphaned: this.inOrphanMode - }; - } - - return this.backupFileService.backupResource(target, this.createSnapshot(), this.versionId, meta); - } - - return Promise.resolve(); + getVersionId(): number { + return this.versionId; } async revert(soft?: boolean): Promise { @@ -275,7 +245,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - async load(options?: ILoadOptions): Promise { + load(options?: ILoadOptions): Promise { this.logService.trace('load() - enter', this.resource); // It is very important to not reload the model when the model is dirty. @@ -284,57 +254,44 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (this.dirty || this.saveSequentializer.hasPendingSave()) { this.logService.trace('load() - exit - without loading because model is dirty or being saved', this.resource); - return this; + return Promise.resolve(this); } // Only for new models we support to load from backup - if (!this.isResolved()) { - const backup = await this.backupFileService.loadBackupResource(this.resource); - - if (this.isResolved()) { - return this; // Make sure meanwhile someone else did not suceed in loading - } - - if (backup) { - try { - return await this.loadFromBackup(backup, options); - } catch (error) { - // ignore error and continue to load as file below - } - } + if (!this.textEditorModel && !this.createTextEditorModelPromise) { + return this.loadFromBackup(options); } // Otherwise load from file resource return this.loadFromFile(options); } - private async loadFromBackup(backup: URI, options?: ILoadOptions): Promise { + private async loadFromBackup(options?: ILoadOptions): Promise { + const backup = await this.backupFileService.loadBackupResource(this.resource); - // Resolve actual backup contents - const resolvedBackup = await this.backupFileService.resolveBackupContent(backup); - - if (this.isResolved()) { - return this; // Make sure meanwhile someone else did not suceed in loading + // Make sure meanwhile someone else did not suceed or start loading + if (this.createTextEditorModelPromise || this.textEditorModel) { + return this.createTextEditorModelPromise || this; } - // Load with backup - this.loadFromContent({ - resource: this.resource, - name: basename(this.resource), - mtime: resolvedBackup.meta ? resolvedBackup.meta.mtime : Date.now(), - size: resolvedBackup.meta ? resolvedBackup.meta.size : 0, - etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown! - value: resolvedBackup.value, - encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding, - isReadonly: false - }, options, true /* from backup */); + // If we have a backup, continue loading with it + if (!!backup) { + const content: ITextFileStreamContent = { + resource: this.resource, + name: basename(this.resource), + mtime: Date.now(), + size: 0, + etag: ETAG_DISABLED, // always allow to save content restored from a backup (see https://github.com/Microsoft/vscode/issues/72343) + value: createTextBufferFactory(''), // will be filled later from backup + encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding, + isReadonly: false + }; - // Restore orphaned flag based on state - if (resolvedBackup.meta && resolvedBackup.meta.orphaned) { - this.setOrphaned(true); + return this.loadWithContent(content, options, backup); } - return this; + // Otherwise load from file + return this.loadFromFile(options); } private async loadFromFile(options?: ILoadOptions): Promise { @@ -345,8 +302,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil let etag: string | undefined; if (forceReadFromDisk) { etag = ETAG_DISABLED; // disable ETag if we enforce to read from disk - } else if (this.lastResolvedFileStat) { - etag = this.lastResolvedFileStat.etag; // otherwise respect etag to support caching + } else if (this.lastResolvedDiskStat) { + etag = this.lastResolvedDiskStat.etag; // otherwise respect etag to support caching } // Ensure to track the versionId before doing a long running operation @@ -364,11 +321,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Clear orphaned state when loading was successful this.setOrphaned(false); - if (currentVersionId !== this.versionId) { - return this; // Make sure meanwhile someone else did not suceed loading + // Guard against the model having changed in the meantime + if (currentVersionId === this.versionId) { + return this.loadWithContent(content, options); } - return this.loadFromContent(content, options); + return this; } catch (error) { const result = error.fileOperationResult; @@ -398,11 +356,37 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - private loadFromContent(content: ITextFileStreamContent, options?: ILoadOptions, fromBackup?: boolean): TextFileEditorModel { + private async loadWithContent(content: ITextFileStreamContent, options?: ILoadOptions, backup?: URI): Promise { + const model = await this.doLoadWithContent(content, backup); + + // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype + const settingsType = this.getTypeIfSettings(); + if (settingsType) { + /* __GDPR__ + "settingsRead" : { + "settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data + } else { + /* __GDPR__ + "fileGet" : { + "${include}": [ + "${FileTelemetryData}" + ] + } + */ + this.telemetryService.publicLog('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER)); + } + + return model; + } + + private doLoadWithContent(content: ITextFileStreamContent, backup?: URI): Promise { this.logService.trace('load() - resolved content', this.resource); // Update our resolved disk stat model - this.updateLastResolvedFileStat({ + this.updateLastResolvedDiskStat({ resource: this.resource, name: content.name, mtime: content.mtime, @@ -425,61 +409,21 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Update Existing Model - if (this.isResolved()) { + if (this.textEditorModel) { this.doUpdateTextModel(content.value); + + return Promise.resolve(this); + } + + // Join an existing request to create the editor model to avoid race conditions + else if (this.createTextEditorModelPromise) { + this.logService.trace('load() - join existing text editor model promise', this.resource); + + return this.createTextEditorModelPromise; } // Create New Model - else { - this.doCreateTextModel(content.resource, content.value, !!fromBackup); - } - - // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype - const settingsType = this.getTypeIfSettings(); - if (settingsType) { - /* __GDPR__ - "settingsRead" : { - "settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data - } else { - /* __GDPR__ - "fileGet" : { - "${include}": [ - "${FileTelemetryData}" - ] - } - */ - this.telemetryService.publicLog('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER)); - } - - return this; - } - - private doCreateTextModel(resource: URI, value: ITextBufferFactory, fromBackup: boolean): void { - this.logService.trace('load() - created text editor model', this.resource); - - // Create model - this.createTextEditorModel(value, resource, this.preferredMode); - - // We restored a backup so we have to set the model as being dirty - // We also want to trigger auto save if it is enabled to simulate the exact same behaviour - // you would get if manually making the model dirty (fixes https://github.com/Microsoft/vscode/issues/16977) - if (fromBackup) { - this.makeDirty(); - if (this.autoSaveAfterMilliesEnabled) { - this.doAutoSave(this.versionId); - } - } - - // Ensure we are not tracking a stale state - else { - this.setDirty(false); - } - - // Model Listeners - this.installModelListeners(); + return this.doCreateTextModel(content.resource, content.value, backup); } private doUpdateTextModel(value: ITextBufferFactory): void { @@ -491,7 +435,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Update model value in a block that ignores model content change events this.blockModelContentChange = true; try { - this.updateTextEditorModel(value, this.preferredMode); + this.updateTextEditorModel(value); } finally { this.blockModelContentChange = false; } @@ -500,6 +444,44 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.updateSavedVersionId(); } + private doCreateTextModel(resource: URI, value: ITextBufferFactory, backup: URI | undefined): Promise { + this.logService.trace('load() - created text editor model', this.resource); + + this.createTextEditorModelPromise = this.doLoadBackup(backup).then(backupContent => { + this.createTextEditorModelPromise = null; + + // Create model + const hasBackupContent = !!backupContent; + this.createTextEditorModel(backupContent ? backupContent : value, resource); + + // We restored a backup so we have to set the model as being dirty + // We also want to trigger auto save if it is enabled to simulate the exact same behaviour + // you would get if manually making the model dirty (fixes https://github.com/Microsoft/vscode/issues/16977) + if (hasBackupContent) { + this.makeDirty(); + if (this.autoSaveAfterMilliesEnabled) { + this.doAutoSave(this.versionId); + } + } + + // Ensure we are not tracking a stale state + else { + this.setDirty(false); + } + + // Model Listeners + this.installModelListeners(); + + return this; + }, error => { + this.createTextEditorModelPromise = null; + + return Promise.reject(error); + }); + + return this.createTextEditorModelPromise; + } + private installModelListeners(): void { // See https://github.com/Microsoft/vscode/issues/30189 @@ -507,11 +489,27 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // where `value` was captured in the content change listener closure scope. // Content Change - if (this.isResolved()) { + if (this.textEditorModel) { this._register(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); } } + private async doLoadBackup(backup: URI | undefined): Promise { + if (!backup) { + return null; + } + + try { + return withUndefinedAsNull(await this.backupFileService.resolveBackupContent(backup)); + } catch (error) { + return null; // ignore errors + } + } + + protected getOrCreateMode(modeService: IModeService, preferredModeIds: string | undefined, firstLineText?: string): ILanguageSelection { + return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); + } + private onModelContentChanged(): void { this.logService.trace(`onModelContentChanged() - enter`, this.resource); @@ -528,7 +526,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // In this case we clear the dirty flag and emit a SAVED event to indicate this state. // Note: we currently only do this check when auto-save is turned off because there you see // a dirty indicator that you want to get rid of when undoing to the saved version. - if (!this.autoSaveAfterMilliesEnabled && this.isResolved() && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { + if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { this.logService.trace('onModelContentChanged() - model content changed back to last saved version', this.resource); // Clear flags @@ -659,7 +657,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Push all edit operations to the undo stack so that the user has a chance to // Ctrl+Z back to the saved version. We only do this when auto-save is turned off - if (!this.autoSaveAfterMilliesEnabled && this.isResolved()) { + if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel) { this.textEditorModel.pushStackElement(); } @@ -689,12 +687,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // saving contents to disk that are stale (see https://github.com/Microsoft/vscode/issues/50942). // To fix this issue, we will not store the contents to disk when we got disposed. if (this.disposed) { - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check - } - - // We require a resolved model from this point on, since we are about to write data to disk. - if (!this.isResolved()) { - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check + return undefined; } // Under certain conditions we do a short-cut of flushing contents to disk when we can assume that @@ -720,12 +713,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Save to Disk // mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering) this.logService.trace(`doSave(${versionId}) - before write()`, this.resource); - return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { + const snapshot = this.createSnapshot(); + if (!snapshot) { + throw new Error('Invalid snapshot'); + } + return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(this.lastResolvedDiskStat.resource, snapshot, { overwriteReadonly: options.overwriteReadonly, overwriteEncoding: options.overwriteEncoding, - mtime: this.lastResolvedFileStat.mtime, + mtime: this.lastResolvedDiskStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedFileStat.etag, + etag: this.lastResolvedDiskStat.etag, writeElevated: options.writeElevated }).then(stat => { this.logService.trace(`doSave(${versionId}) - after write()`, this.resource); @@ -739,7 +736,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Updated resolved stat with updated stat - this.updateLastResolvedFileStat(stat); + this.updateLastResolvedDiskStat(stat); // Cancel any content change event promises as they are no longer valid this.contentChangeEventScheduler.cancel(); @@ -855,22 +852,19 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private doTouch(versionId: number): Promise { - if (!this.isResolved()) { - return Promise.resolve(); + const snapshot = this.createSnapshot(); + if (!snapshot) { + throw new Error('invalid snapshot'); } - return this.saveSequentializer.setPending(versionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { - mtime: this.lastResolvedFileStat.mtime, + return this.saveSequentializer.setPending(versionId, this.textFileService.write(this.lastResolvedDiskStat.resource, snapshot, { + mtime: this.lastResolvedDiskStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedFileStat.etag + etag: this.lastResolvedDiskStat.etag }).then(stat => { // Updated resolved stat with updated stat since touching it might have changed mtime - this.updateLastResolvedFileStat(stat); - - // Emit File Saved Event - this._onDidStateChange.fire(StateChange.SAVED); - + this.updateLastResolvedDiskStat(stat); }, error => onUnexpectedError(error) /* just log any error but do not notify the user since the file was not dirty */)); } @@ -904,23 +898,23 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // in order to find out if the model changed back to a saved version (e.g. // when undoing long enough to reach to a version that is saved and then to // clear the dirty flag) - if (this.isResolved()) { + if (this.textEditorModel) { this.bufferSavedVersionId = this.textEditorModel.getAlternativeVersionId(); } } - private updateLastResolvedFileStat(newFileStat: IFileStatWithMetadata): void { + private updateLastResolvedDiskStat(newVersionOnDiskStat: IFileStatWithMetadata): void { // First resolve - just take - if (!this.lastResolvedFileStat) { - this.lastResolvedFileStat = newFileStat; + if (!this.lastResolvedDiskStat) { + this.lastResolvedDiskStat = newVersionOnDiskStat; } // Subsequent resolve - make sure that we only assign it if the mtime is equal or has advanced. // This prevents race conditions from loading and saving. If a save comes in late after a revert // was called, the mtime could be out of sync. - else if (this.lastResolvedFileStat.mtime <= newFileStat.mtime) { - this.lastResolvedFileStat = newFileStat; + else if (this.lastResolvedDiskStat.mtime <= newVersionOnDiskStat.mtime) { + this.lastResolvedDiskStat = newVersionOnDiskStat; } } @@ -943,6 +937,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.lastSaveAttemptTime; } + getETag(): string | null { + return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag || null : null; + } + hasState(state: ModelState): boolean { switch (state) { case ModelState.CONFLICT: @@ -1024,12 +1022,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return true; } - isResolved(): boolean { // {{SQL CARBON EDIT}} @anthonydresser strict-null-check - return !!this.textEditorModel; + isResolved(): boolean { + return !isUndefinedOrNull(this.lastResolvedDiskStat); } isReadonly(): boolean { - return !!(this.lastResolvedFileStat && this.lastResolvedFileStat.isReadonly); + return !!(this.lastResolvedDiskStat && this.lastResolvedDiskStat.isReadonly); } isDisposed(): boolean { @@ -1041,7 +1039,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } getStat(): IFileStatWithMetadata { - return this.lastResolvedFileStat; + return this.lastResolvedDiskStat; } dispose(): void { @@ -1050,6 +1048,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.inOrphanMode = false; this.inErrorMode = false; + this.createTextEditorModelPromise = null; + this.cancelPendingAutoSave(); super.dispose(); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 6e5b3b6048..3ca04417c6 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -153,7 +153,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Model does not exist else { - const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined, options ? options.mode : undefined); + const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined); modelPromise = model.load(options); // Install state change listener @@ -204,11 +204,6 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Remove from pending loads this.mapResourceToPendingModelLoaders.delete(resource); - // Apply mode if provided - if (options && options.mode) { - resolvedModel.setMode(options.mode); - } - return resolvedModel; } catch (error) { diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index f36e3b0221..445d7d01e6 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -40,7 +40,6 @@ import { trim } from 'vs/base/common/strings'; import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -239,44 +238,59 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private async doBackupAll(dirtyFileModels: ITextFileEditorModel[], untitledResources: URI[]): Promise { // Handle file resources first - await Promise.all(dirtyFileModels.map(model => model.backup())); + await Promise.all(dirtyFileModels.map(async model => { + const snapshot = model.createSnapshot(); + if (snapshot) { + await this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId()); + } + })); // Handle untitled resources - await Promise.all(untitledResources + const untitledModelPromises = untitledResources .filter(untitled => this.untitledEditorService.exists(untitled)) - .map(async untitled => (await this.untitledEditorService.loadOrCreate({ resource: untitled })).backup())); + .map(untitled => this.untitledEditorService.loadOrCreate({ resource: untitled })); + + const untitledModels = await Promise.all(untitledModelPromises); + + await Promise.all(untitledModels.map(async model => { + const snapshot = model.createSnapshot(); + if (snapshot) { + await this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId()); + } + })); } - private async confirmBeforeShutdown(): Promise { - const confirm = await this.confirmSave(); + private confirmBeforeShutdown(): boolean | Promise { + return this.confirmSave().then(confirm => { - // Save - if (confirm === ConfirmResult.SAVE) { - const result = await this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }); + // Save + if (confirm === ConfirmResult.SAVE) { + return this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }).then(result => { + if (result.results.some(r => !r.success)) { + return true; // veto if some saves failed + } - if (result.results.some(r => !r.success)) { - return true; // veto if some saves failed + return this.noVeto({ cleanUpBackups: true }); + }); } - return this.noVeto({ cleanUpBackups: true }); - } + // Don't Save + else if (confirm === ConfirmResult.DONT_SAVE) { - // Don't Save - else if (confirm === ConfirmResult.DONT_SAVE) { + // Make sure to revert untitled so that they do not restore + // see https://github.com/Microsoft/vscode/issues/29572 + this.untitledEditorService.revertAll(); - // Make sure to revert untitled so that they do not restore - // see https://github.com/Microsoft/vscode/issues/29572 - this.untitledEditorService.revertAll(); + return this.noVeto({ cleanUpBackups: true }); + } - return this.noVeto({ cleanUpBackups: true }); - } + // Cancel + else if (confirm === ConfirmResult.CANCEL) { + return true; // veto + } - // Cancel - else if (confirm === ConfirmResult.CANCEL) { - return true; // veto - } - - return false; + return false; + }); } private noVeto(options: { cleanUpBackups: boolean }): boolean | Promise { @@ -489,7 +503,10 @@ export abstract class TextFileService extends Disposable implements ITextFileSer dirtyTargetModelUris.push(targetModelResource); // Backup dirty source model to the target resource it will become later - await sourceModel.backup(targetModelResource); + const snapshot = sourceModel.createSnapshot(); + if (snapshot) { + await this.backupFileService.backupResource(targetModelResource, snapshot, sourceModel.getVersionId()); + } })); } @@ -740,14 +757,14 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private getFileModels(arg1?: URI | URI[]): ITextFileEditorModel[] { if (Array.isArray(arg1)) { const models: ITextFileEditorModel[] = []; - arg1.forEach(resource => { + (arg1).forEach(resource => { models.push(...this.getFileModels(resource)); }); return models; } - return this._models.getAll(arg1); + return this._models.getAll(arg1); } private getDirtyFileModels(resources?: URI | URI[]): ITextFileEditorModel[] { @@ -856,12 +873,17 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // take over encoding, mode and model value from source model targetModel.updatePreferredEncoding(sourceModel.getEncoding()); - if (sourceModel.isResolved() && targetModel.isResolved()) { - this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); + if (targetModel.textEditorModel) { + const snapshot = sourceModel.createSnapshot(); + if (snapshot) { + this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(snapshot)); + } - const mode = sourceModel.textEditorModel.getLanguageIdentifier(); - if (mode.language !== PLAINTEXT_MODE_ID) { - targetModel.textEditorModel.setMode(mode); // only use if more specific than plain/text + if (sourceModel.textEditorModel) { + const language = sourceModel.textEditorModel.getLanguageIdentifier(); + if (language.id > 1) { + targetModel.textEditorModel.setMode(language); // only use if more specific than plain/text + } } } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 8c46a858ac..729429536d 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IEncodingSupport, ConfirmResult, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; +import { IEncodingSupport, ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -367,11 +367,6 @@ export interface IModelLoadOrCreateOptions { */ reason?: LoadReason; - /** - * The language mode to use for the model text content. - */ - mode?: string; - /** * The encoding to use when resolving the model text content. */ @@ -448,15 +443,19 @@ export interface ILoadOptions { reason?: LoadReason; } -export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport { +export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { readonly onDidContentChange: Event; readonly onDidStateChange: Event; + getVersionId(): number; + getResource(): URI; hasState(state: ModelState): boolean; + getETag(): string | null; + updatePreferredEncoding(encoding: string): void; save(options?: ISaveOptions): Promise; @@ -465,17 +464,16 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport revert(soft?: boolean): Promise; - backup(target?: URI): Promise; + createSnapshot(): ITextSnapshot | null; isDirty(): boolean; - isResolved(): this is IResolvedTextFileEditorModel; + isResolved(): boolean; isDisposed(): boolean; } export interface IResolvedTextFileEditorModel extends ITextFileEditorModel { - readonly textEditorModel: ITextModel; createSnapshot(): ITextSnapshot; diff --git a/src/vs/workbench/services/textfile/node/textFileService.ts b/src/vs/workbench/services/textfile/node/textFileService.ts index d5b739af9c..b246b83ff4 100644 --- a/src/vs/workbench/services/textfile/node/textFileService.ts +++ b/src/vs/workbench/services/textfile/node/textFileService.ts @@ -11,7 +11,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { URI } from 'vs/base/common/uri'; import { IFileStatWithMetadata, ICreateFileOptions, FileOperationError, FileOperationResult, IFileStreamContent, IFileService } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; -import { exists, stat, chmod, rimraf, MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/base/node/pfs'; +import { exists, stat, chmod, rimraf } from 'vs/base/node/pfs'; import { join, dirname } from 'vs/base/common/path'; import { isMacintosh, isLinux } from 'vs/base/common/platform'; import product from 'vs/platform/product/node/product'; @@ -26,6 +26,7 @@ import { VSBufferReadable, VSBuffer, VSBufferReadableStream } from 'vs/base/comm import { Readable } from 'stream'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; +import { MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/platform/files/node/fileConstants'; import { ITextSnapshot } from 'vs/editor/common/model'; export class NodeTextFileService extends TextFileService { diff --git a/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts b/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts index 1780a2570c..acbc9cda7d 100644 --- a/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts @@ -17,7 +17,7 @@ import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiatio export class TextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: ServiceIdentifier; private remoteEnvironment: IRemoteAgentEnvironment | null = null; diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index cb870fd3d3..a88e9ab674 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -14,7 +14,6 @@ import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/commo import { FileOperationResult, FileOperationError, IFileService } from 'vs/platform/files/common/files'; import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; -import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; class ServiceAccessor { constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService, @IFileService public fileService: TestFileService) { @@ -45,53 +44,25 @@ suite('Files - TextFileEditorModel', () => { accessor.fileService.setContent(content); }); - test('save', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + test('Save', async function () { + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); model.textEditorModel!.setValue('bar'); assert.ok(getLastModifiedTime(model) <= Date.now()); - let savedEvent = false; - model.onDidStateChange(e => { - if (e === StateChange.SAVED) { - savedEvent = true; - } - }); - await model.save(); assert.ok(model.getLastSaveAttemptTime() <= Date.now()); assert.ok(!model.isDirty()); - assert.ok(savedEvent); - - model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); - }); - - test('save - touching also emits saved event', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); - - await model.load(); - - let savedEvent = false; - model.onDidStateChange(e => { - if (e === StateChange.SAVED) { - savedEvent = true; - } - }); - - await model.save({ force: true }); - - assert.ok(savedEvent); model.dispose(); assert.ok(!accessor.modelService.getModel(model.getResource())); }); test('setEncoding - encode', function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); model.setEncoding('utf8', EncodingMode.Encode); // no-op assert.equal(getLastModifiedTime(model), -1); @@ -104,7 +75,7 @@ suite('Files - TextFileEditorModel', () => { }); test('setEncoding - decode', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); model.setEncoding('utf16', EncodingMode.Decode); @@ -113,24 +84,8 @@ suite('Files - TextFileEditorModel', () => { model.dispose(); }); - test('create with mode', async function () { - const mode = 'text-file-model-test'; - ModesRegistry.registerLanguage({ - id: mode, - }); - - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', mode); - - await model.load(); - - assert.equal(model.textEditorModel!.getModeId(), mode); - - model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); - }); - test('disposes when underlying model is destroyed', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); @@ -139,7 +94,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load does not trigger save', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index.txt'), 'utf8', undefined); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index.txt'), 'utf8'); assert.ok(model.hasState(ModelState.SAVED)); model.onDidStateChange(e => { @@ -153,7 +108,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load returns dirty model as long as model is dirty', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); model.textEditorModel!.setValue('foo'); @@ -168,7 +123,7 @@ suite('Files - TextFileEditorModel', () => { test('Revert', async function () { let eventCounter = 0; - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); model.onDidStateChange(e => { if (e === StateChange.REVERTED) { @@ -190,7 +145,7 @@ suite('Files - TextFileEditorModel', () => { test('Revert (soft)', async function () { let eventCounter = 0; - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); model.onDidStateChange(e => { if (e === StateChange.REVERTED) { @@ -210,7 +165,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load and undo turns model dirty', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); accessor.fileService.setContent('Hello Change'); @@ -220,7 +175,7 @@ suite('Files - TextFileEditorModel', () => { }); test('File not modified error is handled gracefully', async function () { - let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); @@ -235,7 +190,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load error is handled gracefully if model already exists', async function () { - let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); await model.load(); accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_NOT_FOUND)); @@ -281,7 +236,7 @@ suite('Files - TextFileEditorModel', () => { test('Save Participant', async function () { let eventCounter = 0; - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); model.onDidStateChange(e => { if (e === StateChange.SAVED) { @@ -311,7 +266,7 @@ suite('Files - TextFileEditorModel', () => { test('Save Participant, async participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); TextFileEditorModel.setSaveParticipant({ participate: (model) => { @@ -329,7 +284,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Save Participant, bad participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); TextFileEditorModel.setSaveParticipant({ participate: (model) => { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 96841bc45c..c8081048b0 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -13,7 +13,6 @@ import { IFileService, FileChangesEvent, FileChangeType } from 'vs/platform/file import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; import { toResource } from 'vs/base/test/common/utils'; -import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; export class TestTextFileEditorModelManager extends TextFileEditorModelManager { @@ -43,9 +42,9 @@ suite('Files - TextFileEditorModelManager', () => { test('add, remove, clear, get, getAll', function () { const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); - const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8', undefined); - const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8', undefined); - const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8', undefined); + const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8'); + const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8'); + const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8'); manager.add(URI.file('/test.html'), model1); manager.add(URI.file('/some/other.html'), model2); @@ -118,9 +117,9 @@ suite('Files - TextFileEditorModelManager', () => { test('removed from cache when model disposed', function () { const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); - const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8', undefined); - const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8', undefined); - const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8', undefined); + const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8'); + const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8'); + const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8'); manager.add(URI.file('/test.html'), model1); manager.add(URI.file('/some/other.html'), model2); @@ -291,24 +290,4 @@ suite('Files - TextFileEditorModelManager', () => { assert.ok(model.isDisposed()); manager.dispose(); }); - - test('mode', async function () { - const mode = 'text-file-model-manager-test'; - ModesRegistry.registerLanguage({ - id: mode, - }); - - const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); - - const resource = toResource.call(this, '/path/index_something.txt'); - - let model = await manager.loadOrCreate(resource, { mode }); - assert.equal(model.textEditorModel!.getModeId(), mode); - - model = await manager.loadOrCreate(resource, { mode: 'text' }); - assert.equal(model.textEditorModel!.getModeId(), PLAINTEXT_MODE_ID); - - manager.disposeModel((model as TextFileEditorModel)); - manager.dispose(); - }); }); \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 3ad5111692..b4bdb0c4b1 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -65,8 +65,8 @@ suite('Files - TextFileService', () => { accessor.untitledEditorService.revertAll(); }); - test('confirm onWillShutdown - no veto', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + test('confirm onWillShutdown - no veto', function () { + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const event = new BeforeShutdownEventImpl(); @@ -76,12 +76,14 @@ suite('Files - TextFileService', () => { if (typeof veto === 'boolean') { assert.ok(!veto); } else { - assert.ok(!(await veto)); + veto.then(veto => { + assert.ok(!veto); + }); } }); test('confirm onWillShutdown - veto if user cancels', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -97,7 +99,7 @@ suite('Files - TextFileService', () => { }); test('confirm onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -123,7 +125,7 @@ suite('Files - TextFileService', () => { }); test('confirm onWillShutdown - save (hot.exit: off)', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -142,7 +144,7 @@ suite('Files - TextFileService', () => { }); test('isDirty/getDirty - files and untitled', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -169,7 +171,7 @@ suite('Files - TextFileService', () => { }); test('save - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -185,11 +187,11 @@ suite('Files - TextFileService', () => { test('save - UNC path', async function () { const untitledUncUri = URI.from({ scheme: 'untitled', authority: 'server', path: '/share/path/file.txt' }); - model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const mockedFileUri = untitledUncUri.with({ scheme: Schemas.file }); - const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8', undefined); + const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8'); const loadOrCreateStub = sinon.stub(accessor.textFileService.models, 'loadOrCreate', () => Promise.resolve(mockedEditorInput)); sinon.stub(accessor.untitledEditorService, 'exists', () => true); @@ -209,7 +211,7 @@ suite('Files - TextFileService', () => { }); test('saveAll - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -226,7 +228,7 @@ suite('Files - TextFileService', () => { }); test('saveAs - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -242,7 +244,7 @@ suite('Files - TextFileService', () => { }); test('revert - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -258,7 +260,7 @@ suite('Files - TextFileService', () => { }); test('delete - dirty file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -272,8 +274,8 @@ suite('Files - TextFileService', () => { }); test('move - dirty file', async function () { - let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_target.txt'), 'utf8', undefined); + let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_target.txt'), 'utf8'); (accessor.textFileService.models).add(sourceModel.getResource(), sourceModel); (accessor.textFileService.models).add(targetModel.getResource(), targetModel); @@ -395,7 +397,7 @@ suite('Files - TextFileService', () => { }); async function hotExitTest(this: any, setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean): Promise { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); (accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index d276b52b3f..587a60d641 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -53,7 +53,7 @@ suite('Workbench - TextModelResolverService', () => { accessor.untitledEditorService.revertAll(); }); - test('resolve resource', async () => { + test('resolve resource', function () { const dispose = accessor.textModelResolverService.registerTextModelContentProvider('test', { provideTextContent: function (resource: URI): Promise { if (resource.scheme === 'test') { @@ -67,60 +67,67 @@ suite('Workbench - TextModelResolverService', () => { }); let resource = URI.from({ scheme: 'test', authority: null!, path: 'thePath' }); - let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, undefined); + let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - const model = await input.resolve(); - assert.ok(model); - assert.equal(snapshotToString(((model as ResourceEditorModel).createSnapshot()!)), 'Hello Test'); - let disposed = false; - let disposedPromise = new Promise(resolve => { - Event.once(model.onDispose)(() => { - disposed = true; - resolve(); + return input.resolve().then(async model => { + assert.ok(model); + assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()!), 'Hello Test'); + + let disposed = false; + let disposedPromise = new Promise(resolve => { + Event.once(model.onDispose)(() => { + disposed = true; + resolve(); + }); + }); + input.dispose(); + await disposedPromise; + assert.equal(disposed, true); + + dispose.dispose(); + }); + }); + + test('resolve file', function () { + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8'); + (accessor.textFileService.models).add(model.getResource(), model); + + return model.load().then(() => { + return accessor.textModelResolverService.createModelReference(model.getResource()).then(ref => { + const model = ref.object; + const editorModel = model.textEditorModel; + + assert.ok(editorModel); + assert.equal(editorModel.getValue(), 'Hello Html'); + + let disposed = false; + Event.once(model.onDispose)(() => { + disposed = true; + }); + + ref.dispose(); + return timeout(0).then(() => { // due to the reference resolving the model first which is async + assert.equal(disposed, true); + }); }); }); - input.dispose(); - - await disposedPromise; - assert.equal(disposed, true); - dispose.dispose(); }); - test('resolve file', async function () { - const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(textModel.getResource(), textModel); - - await textModel.load(); - - const ref = await accessor.textModelResolverService.createModelReference(textModel.getResource()); - - const model = ref.object; - const editorModel = model.textEditorModel; - - assert.ok(editorModel); - assert.equal(editorModel.getValue(), 'Hello Html'); - - let disposed = false; - Event.once(model.onDispose)(() => { - disposed = true; - }); - - ref.dispose(); - await timeout(0); // due to the reference resolving the model first which is async - assert.equal(disposed, true); - }); - - test('resolve untitled', async () => { + test('resolve untitled', function () { const service = accessor.untitledEditorService; const input = service.createOrGet(); - await input.resolve(); - const ref = await accessor.textModelResolverService.createModelReference(input.getResource()); - const model = ref.object; - const editorModel = model.textEditorModel; - assert.ok(editorModel); - ref.dispose(); - input.dispose(); + return input.resolve().then(() => { + return accessor.textModelResolverService.createModelReference(input.getResource()).then(ref => { + const model = ref.object; + const editorModel = model.textEditorModel; + + assert.ok(editorModel); + ref.dispose(); + + input.dispose(); + }); + }); }); test('even loading documents should be refcounted', async () => { @@ -128,12 +135,12 @@ suite('Workbench - TextModelResolverService', () => { let waitForIt = new Promise(c => resolveModel = c); const disposable = accessor.textModelResolverService.registerTextModelContentProvider('test', { - provideTextContent: async (resource: URI): Promise => { - await waitForIt; - - let modelContent = 'Hello Test'; - let languageSelection = accessor.modeService.create('json'); - return accessor.modelService.createModel(modelContent, languageSelection, resource); + provideTextContent: (resource: URI): Promise => { + return waitForIt.then(_ => { + let modelContent = 'Hello Test'; + let languageSelection = accessor.modeService.create('json'); + return accessor.modelService.createModel(modelContent, languageSelection, resource); + }); } }); diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index e57ae79388..8fe6db11e1 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -21,7 +21,7 @@ export const IUntitledEditorService = createDecorator('u export interface IModelLoadOrCreateOptions { resource?: URI; - mode?: string; + modeId?: string; initialValue?: string; encoding?: string; useResourcePath?: boolean; @@ -29,7 +29,7 @@ export interface IModelLoadOrCreateOptions { export interface IUntitledEditorService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; /** * Events for when untitled editors content changes (e.g. any keystroke). @@ -84,7 +84,7 @@ export interface IUntitledEditorService { * It is valid to pass in a file resource. In that case the path will be used as identifier. * The use case is to be able to create a new file with a specific path with VSCode. */ - createOrGet(resource?: URI, mode?: string, initialValue?: string, encoding?: string): UntitledEditorInput; + createOrGet(resource?: URI, modeId?: string, initialValue?: string, encoding?: string): UntitledEditorInput; /** * Creates a new untitled model with the optional resource URI or returns an existing one @@ -191,10 +191,10 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor } loadOrCreate(options: IModelLoadOrCreateOptions = Object.create(null)): Promise { - return this.createOrGet(options.resource, options.mode, options.initialValue, options.encoding, options.useResourcePath).resolve(); + return this.createOrGet(options.resource, options.modeId, options.initialValue, options.encoding, options.useResourcePath).resolve(); } - createOrGet(resource?: URI, mode?: string, initialValue?: string, encoding?: string, hasAssociatedFilePath: boolean = false): UntitledEditorInput { + createOrGet(resource?: URI, modeId?: string, initialValue?: string, encoding?: string, hasAssociatedFilePath: boolean = false): UntitledEditorInput { if (resource) { // Massage resource if it comes with known file based resource @@ -214,47 +214,44 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor } // Create new otherwise - return this.doCreate(resource, hasAssociatedFilePath, mode, initialValue, encoding); + return this.doCreate(resource, hasAssociatedFilePath, modeId, initialValue, encoding); } - private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, mode?: string, initialValue?: string, encoding?: string): UntitledEditorInput { - let untitledResource: URI; - if (resource) { - untitledResource = resource; - } else { + private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string, initialValue?: string, encoding?: string): UntitledEditorInput { + if (!resource) { // Create new taking a resource URI that is not already taken let counter = this.mapResourceToInput.size + 1; do { - untitledResource = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}` }); + resource = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}` }); counter++; - } while (this.mapResourceToInput.has(untitledResource)); + } while (this.mapResourceToInput.has(resource)); } // Look up default language from settings if any - if (!mode && !hasAssociatedFilePath) { + if (!modeId && !hasAssociatedFilePath) { const configuration = this.configurationService.getValue(); if (configuration.files && configuration.files.defaultLanguage) { - mode = configuration.files.defaultLanguage; + modeId = configuration.files.defaultLanguage; } } - const input = this.instantiationService.createInstance(UntitledEditorInput, untitledResource, hasAssociatedFilePath, mode, initialValue, encoding); + const input = this.instantiationService.createInstance(UntitledEditorInput, resource, hasAssociatedFilePath, modeId, initialValue, encoding); const contentListener = input.onDidModelChangeContent(() => { - this._onDidChangeContent.fire(untitledResource); + this._onDidChangeContent.fire(resource!); }); const dirtyListener = input.onDidChangeDirty(() => { - this._onDidChangeDirty.fire(untitledResource); + this._onDidChangeDirty.fire(resource!); }); const encodingListener = input.onDidModelChangeEncoding(() => { - this._onDidChangeEncoding.fire(untitledResource); + this._onDidChangeEncoding.fire(resource!); }); const disposeListener = input.onDispose(() => { - this._onDidDisposeModel.fire(untitledResource); + this._onDidDisposeModel.fire(resource!); }); // Remove from cache on dispose @@ -269,7 +266,7 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor }); // Add to cache - this.mapResourceToInput.set(untitledResource, input); + this.mapResourceToInput.set(resource, input); return input; } diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index c667845604..5906a7e3a5 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -86,7 +86,7 @@ class MyResourceInput extends ResourceEditorInput { } suite('Workbench base editor', () => { - test('BaseEditor API', async () => { + test('BaseEditor API', function () { let e = new MyEditor(NullTelemetryService); let input = new MyOtherInput(); let options = new EditorOptions(); @@ -94,24 +94,25 @@ suite('Workbench base editor', () => { assert(!e.isVisible()); assert(!e.input); assert(!e.options); + return e.setInput(input, options, CancellationToken.None).then(() => { + assert.strictEqual(input, e.input); + assert.strictEqual(options, e.options); - await e.setInput(input, options, CancellationToken.None); - assert.strictEqual(input, e.input); - assert.strictEqual(options, e.options); - const group = new TestEditorGroup(1); - e.setVisible(true, group); - assert(e.isVisible()); - assert.equal(e.group, group); - input.onDispose(() => { - assert(false); + const group = new TestEditorGroup(1); + e.setVisible(true, group); + assert(e.isVisible()); + assert.equal(e.group, group); + input.onDispose(() => { + assert(false); + }); + e.dispose(); + e.clearInput(); + e.setVisible(false, group); + assert(!e.isVisible()); + assert(!e.input); + assert(!e.options); + assert(!e.getControl()); }); - e.dispose(); - e.clearInput(); - e.setVisible(false, group); - assert(!e.isVisible()); - assert(!e.input); - assert(!e.options); - assert(!e.getControl()); }); test('EditorDescriptor', () => { @@ -153,10 +154,10 @@ suite('Workbench base editor', () => { let inst = new TestInstantiationService(); - const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); assert.strictEqual(editor.getId(), 'myEditor'); - const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); + const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); assert.strictEqual(otherEditor.getId(), 'myOtherEditor'); (EditorRegistry).setEditors(oldEditors); @@ -172,7 +173,7 @@ suite('Workbench base editor', () => { let inst = new TestInstantiationService(); - const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); assert.strictEqual('myOtherEditor', editor.getId()); (EditorRegistry).setEditors(oldEditors); diff --git a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts index 07a0555861..6367574260 100644 --- a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts @@ -35,7 +35,7 @@ suite('Workbench editor model', () => { accessor = instantiationService.createInstance(ServiceAccessor); }); - test('TextDiffEditorModel', async () => { + test('TextDiffEditorModel', () => { const dispose = accessor.textModelResolverService.registerTextModelContentProvider('test', { provideTextContent: function (resource: URI): Promise { if (resource.scheme === 'test') { @@ -48,26 +48,27 @@ suite('Workbench editor model', () => { } }); - let input = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' }), undefined); - let otherInput = instantiationService.createInstance(ResourceEditorInput, 'name2', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' }), undefined); + let input = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' })); + let otherInput = instantiationService.createInstance(ResourceEditorInput, 'name2', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' })); let diffInput = new DiffEditorInput('name', 'description', input, otherInput); - let model = await diffInput.resolve() as TextDiffEditorModel; + return diffInput.resolve().then((model: any) => { + assert(model); + assert(model instanceof TextDiffEditorModel); - assert(model); - assert(model instanceof TextDiffEditorModel); + let diffEditorModel = model.textDiffEditorModel; + assert(diffEditorModel.original); + assert(diffEditorModel.modified); - let diffEditorModel = model.textDiffEditorModel!; - assert(diffEditorModel.original); - assert(diffEditorModel.modified); + return diffInput.resolve().then((model: any) => { + assert(model.isResolved()); - model = await diffInput.resolve() as TextDiffEditorModel; - assert(model.isResolved()); + assert(diffEditorModel !== model.textDiffEditorModel); + diffInput.dispose(); + assert(!model.textDiffEditorModel); - assert(diffEditorModel !== model.textDiffEditorModel); - diffInput.dispose(); - assert(!model.textDiffEditorModel); - - dispose.dispose(); + dispose.dispose(); + }); + }); }); }); diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index 727b95eb42..453e5d3707 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -111,17 +111,27 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { } getTypeId() { return 'testFileEditorInputForGroups'; } resolve(): Promise { return Promise.resolve(null!); } - setEncoding(encoding: string) { } - getEncoding(): string { return null!; } - setPreferredEncoding(encoding: string) { } - getResource(): URI { return this.resource; } - setForceOpenAsBinary(): void { } - setMode(mode: string) { } - setPreferredMode(mode: string) { } matches(other: TestFileEditorInput): boolean { return other && this.id === other.id && other instanceof TestFileEditorInput; } + + setEncoding(encoding: string) { + } + + getEncoding(): string { + return null!; + } + + setPreferredEncoding(encoding: string) { + } + + getResource(): URI { + return this.resource; + } + + setForceOpenAsBinary(): void { + } } function input(id = String(index++), nonSerializable?: boolean, resource?: URI): EditorInput { diff --git a/src/vs/workbench/test/common/editor/editorModel.test.ts b/src/vs/workbench/test/common/editor/editorModel.test.ts index c758eec3e6..8f1f6660e9 100644 --- a/src/vs/workbench/test/common/editor/editorModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorModel.test.ts @@ -21,8 +21,8 @@ import { TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTe class MyEditorModel extends EditorModel { } class MyTextEditorModel extends BaseTextEditorModel { - public createTextEditorModel(value: ITextBufferFactory, resource?: URI, preferredMode?: string) { - return super.createTextEditorModel(value, resource, preferredMode); + public createTextEditorModel(value: ITextBufferFactory, resource?: URI, modeId?: string) { + return super.createTextEditorModel(value, resource, modeId); } isReadonly(): boolean { @@ -40,7 +40,7 @@ suite('Workbench editor model', () => { modeService = instantiationService.stub(IModeService, ModeServiceImpl); }); - test('EditorModel', async () => { + test('EditorModel', () => { let counter = 0; let m = new MyEditorModel(); @@ -50,23 +50,25 @@ suite('Workbench editor model', () => { counter++; }); - const model = await m.load(); - assert(model === m); - assert.strictEqual(m.isResolved(), true); - m.dispose(); - assert.equal(counter, 1); + return m.load().then(model => { + assert(model === m); + assert.strictEqual(m.isResolved(), true); + m.dispose(); + assert.equal(counter, 1); + }); }); - test('BaseTextEditorModel', async () => { + test('BaseTextEditorModel', () => { let modelService = stubModelService(instantiationService); let m = new MyTextEditorModel(modelService, modeService); - const model = await m.load() as MyTextEditorModel; - - assert(model === m); - model.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain'); - assert.strictEqual(m.isResolved(), true); - m.dispose(); + return m.load().then((model: MyTextEditorModel) => { + assert(model === m); + model.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain'); + assert.strictEqual(m.isResolved(), true); + }).then(() => { + m.dispose(); + }); }); function stubModelService(instantiationService: TestInstantiationService): IModelService { diff --git a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts index fff7ee2b6a..995e9461e4 100644 --- a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts @@ -12,16 +12,17 @@ import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestSe import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; -import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; class ServiceAccessor { constructor( @IModelService public modelService: IModelService, @IModeService public modeService: IModeService - ) { } + ) { + } } suite('Workbench resource editor input', () => { + let instantiationService: IInstantiationService; let accessor: ServiceAccessor; @@ -30,33 +31,14 @@ suite('Workbench resource editor input', () => { accessor = instantiationService.createInstance(ServiceAccessor); }); - test('basics', async () => { - const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); + test('simple', () => { + let resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); + let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, undefined); - - const model = await input.resolve(); - - assert.ok(model); - assert.equal(snapshotToString(((model as ResourceEditorModel).createSnapshot()!)), 'function test() {}'); - }); - - test('custom mode', async () => { - ModesRegistry.registerLanguage({ - id: 'resource-input-test', + return input.resolve().then(model => { + assert.ok(model); + assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()!), 'function test() {}'); }); - - const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); - accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); - - const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, 'resource-input-test'); - - const model = await input.resolve(); - assert.ok(model); - assert.equal(model.textEditorModel.getModeId(), 'resource-input-test'); - - input.setMode('text'); - assert.equal(model.textEditorModel.getModeId(), PLAINTEXT_MODE_ID); }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/common/editor/untitledEditor.test.ts b/src/vs/workbench/test/common/editor/untitledEditor.test.ts index 1c2d513a99..5f7008bdde 100644 --- a/src/vs/workbench/test/common/editor/untitledEditor.test.ts +++ b/src/vs/workbench/test/common/editor/untitledEditor.test.ts @@ -16,7 +16,6 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { timeout } from 'vs/base/common/async'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; -import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; export class TestUntitledEditorService extends UntitledEditorService { get(resource: URI) { return super.get(resource); } @@ -46,7 +45,7 @@ suite('Workbench untitled editors', () => { accessor.untitledEditorService.dispose(); }); - test('Untitled Editor Service', async (done) => { + test('Untitled Editor Service', function (done) { const service = accessor.untitledEditorService; assert.equal(service.getAll().length, 0); @@ -69,35 +68,36 @@ suite('Workbench untitled editors', () => { assert.equal(service.getAll().length, 1); // dirty - const model = await input2.resolve(); + input2.resolve().then(model => { + assert.ok(!service.isDirty(input2.getResource())); - assert.ok(!service.isDirty(input2.getResource())); + const listener = service.onDidChangeDirty(resource => { + listener.dispose(); - const listener = service.onDidChangeDirty(resource => { - listener.dispose(); + assert.equal(resource.toString(), input2.getResource().toString()); - assert.equal(resource.toString(), input2.getResource().toString()); + assert.ok(service.isDirty(input2.getResource())); + assert.equal(service.getDirty()[0].toString(), input2.getResource().toString()); + assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); + assert.equal(service.getDirty([input1.getResource()]).length, 0); - assert.ok(service.isDirty(input2.getResource())); - assert.equal(service.getDirty()[0].toString(), input2.getResource().toString()); - assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); - assert.equal(service.getDirty([input1.getResource()]).length, 0); + service.revertAll(); + assert.equal(service.getAll().length, 0); + assert.ok(!input2.isDirty()); + assert.ok(!model.isDirty()); - service.revertAll(); - assert.equal(service.getAll().length, 0); - assert.ok(!input2.isDirty()); - assert.ok(!model.isDirty()); + input2.dispose(); - input2.dispose(); + assert.ok(!service.exists(input2.getResource())); - assert.ok(!service.exists(input2.getResource())); - done(); - }); + done(); + }); - model.textEditorModel.setValue('foo bar'); + model.textEditorModel.setValue('foo bar'); + }, err => done(err)); }); - test('Untitled with associated resource', () => { + test('Untitled with associated resource', function () { const service = accessor.untitledEditorService; const file = URI.file(join('C:\\', '/foo/file.txt')); const untitled = service.createOrGet(file); @@ -107,49 +107,53 @@ suite('Workbench untitled editors', () => { untitled.dispose(); }); - test('Untitled no longer dirty when content gets empty', async () => { + test('Untitled no longer dirty when content gets empty', function () { const service = accessor.untitledEditorService; const input = service.createOrGet(); // dirty - const model = await input.resolve(); - model.textEditorModel.setValue('foo bar'); - assert.ok(model.isDirty()); - model.textEditorModel.setValue(''); - assert.ok(!model.isDirty()); - input.dispose(); + return input.resolve().then(model => { + model.textEditorModel.setValue('foo bar'); + assert.ok(model.isDirty()); + + model.textEditorModel.setValue(''); + assert.ok(!model.isDirty()); + + input.dispose(); + }); }); - test('Untitled via loadOrCreate', async () => { + test('Untitled via loadOrCreate', function () { const service = accessor.untitledEditorService; + service.loadOrCreate().then(model1 => { + model1.textEditorModel!.setValue('foo bar'); + assert.ok(model1.isDirty()); - const model1 = await service.loadOrCreate(); + model1.textEditorModel!.setValue(''); + assert.ok(!model1.isDirty()); - model1.textEditorModel!.setValue('foo bar'); - assert.ok(model1.isDirty()); + return service.loadOrCreate({ initialValue: 'Hello World' }).then(model2 => { + assert.equal(snapshotToString(model2.createSnapshot()!), 'Hello World'); - model1.textEditorModel!.setValue(''); - assert.ok(!model1.isDirty()); + const input = service.createOrGet(); - const model2 = await service.loadOrCreate({ initialValue: 'Hello World' }); - assert.equal(snapshotToString(model2.createSnapshot()!), 'Hello World'); + return service.loadOrCreate({ resource: input.getResource() }).then(model3 => { + assert.equal(model3.getResource().toString(), input.getResource().toString()); - const input = service.createOrGet(); + const file = URI.file(join('C:\\', '/foo/file44.txt')); + return service.loadOrCreate({ resource: file }).then(model4 => { + assert.ok(service.hasAssociatedFilePath(model4.getResource())); + assert.ok(model4.isDirty()); - const model3 = await service.loadOrCreate({ resource: input.getResource() }); - - assert.equal(model3.getResource().toString(), input.getResource().toString()); - - const file = URI.file(join('C:\\', '/foo/file44.txt')); - const model4 = await service.loadOrCreate({ resource: file }); - assert.ok(service.hasAssociatedFilePath(model4.getResource())); - assert.ok(model4.isDirty()); - - model1.dispose(); - model2.dispose(); - model3.dispose(); - model4.dispose(); - input.dispose(); + model1.dispose(); + model2.dispose(); + model3.dispose(); + model4.dispose(); + input.dispose(); + }); + }); + }); + }); }); test('Untitled suggest name', function () { @@ -159,31 +163,24 @@ suite('Workbench untitled editors', () => { assert.ok(service.suggestFileName(input.getResource())); }); - test('Untitled with associated path remains dirty when content gets empty', async () => { + test('Untitled with associated path remains dirty when content gets empty', function () { const service = accessor.untitledEditorService; const file = URI.file(join('C:\\', '/foo/file.txt')); const input = service.createOrGet(file); // dirty - const model = await input.resolve(); - model.textEditorModel.setValue('foo bar'); - assert.ok(model.isDirty()); - model.textEditorModel.setValue(''); - assert.ok(model.isDirty()); - input.dispose(); + return input.resolve().then(model => { + model.textEditorModel.setValue('foo bar'); + assert.ok(model.isDirty()); + + model.textEditorModel.setValue(''); + assert.ok(model.isDirty()); + + input.dispose(); + }); }); - test('Untitled with initial content is dirty', async () => { - const service = accessor.untitledEditorService; - const input = service.createOrGet(undefined, undefined, 'Hello World'); - - // dirty - const model = await input.resolve(); - assert.ok(model.isDirty()); - input.dispose(); - }); - - test('Untitled created with files.defaultLanguage setting', () => { + test('Untitled created with files.defaultLanguage setting', function () { const defaultLanguage = 'javascript'; const config = accessor.testConfigurationService; config.setUserConfiguration('files', { 'defaultLanguage': defaultLanguage }); @@ -191,52 +188,30 @@ suite('Workbench untitled editors', () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); - assert.equal(input.getMode(), defaultLanguage); + assert.equal(input.getModeId(), defaultLanguage); config.setUserConfiguration('files', { 'defaultLanguage': undefined }); input.dispose(); }); - test('Untitled created with mode overrides files.defaultLanguage setting', () => { - const mode = 'typescript'; + test('Untitled created with modeId overrides files.defaultLanguage setting', function () { + const modeId = 'typescript'; const defaultLanguage = 'javascript'; const config = accessor.testConfigurationService; config.setUserConfiguration('files', { 'defaultLanguage': defaultLanguage }); const service = accessor.untitledEditorService; - const input = service.createOrGet(null!, mode); + const input = service.createOrGet(null!, modeId); - assert.equal(input.getMode(), mode); + assert.equal(input.getModeId(), modeId); config.setUserConfiguration('files', { 'defaultLanguage': undefined }); input.dispose(); }); - test('Untitled can change mode afterwards', async () => { - const mode = 'untitled-input-test'; - - ModesRegistry.registerLanguage({ - id: mode, - }); - - const service = accessor.untitledEditorService; - const input = service.createOrGet(null!, mode); - - assert.equal(input.getMode(), mode); - - const model = await input.resolve(); - assert.equal(model.getMode(), mode); - - input.setMode('text'); - - assert.equal(input.getMode(), PLAINTEXT_MODE_ID); - - input.dispose(); - }); - - test('encoding change event', async () => { + test('encoding change event', function () { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -248,13 +223,16 @@ suite('Workbench untitled editors', () => { }); // dirty - const model = await input.resolve(); - model.setEncoding('utf16'); - assert.equal(counter, 1); - input.dispose(); + return input.resolve().then(model => { + model.setEncoding('utf16'); + + assert.equal(counter, 1); + + input.dispose(); + }); }); - test('onDidChangeContent event', async () => { + test('onDidChangeContent event', () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -267,32 +245,39 @@ suite('Workbench untitled editors', () => { assert.equal(r.toString(), input.getResource().toString()); }); - const model = await input.resolve(); - model.textEditorModel.setValue('foo'); - assert.equal(counter, 0, 'Dirty model should not trigger event immediately'); + return input.resolve().then(model => { + model.textEditorModel.setValue('foo'); + assert.equal(counter, 0, 'Dirty model should not trigger event immediately'); - await timeout(3); - assert.equal(counter, 1, 'Dirty model should trigger event'); - model.textEditorModel.setValue('bar'); + return timeout(3).then(() => { + assert.equal(counter, 1, 'Dirty model should trigger event'); - await timeout(3); - assert.equal(counter, 2, 'Content change when dirty should trigger event'); - model.textEditorModel.setValue(''); + model.textEditorModel.setValue('bar'); + return timeout(3).then(() => { + assert.equal(counter, 2, 'Content change when dirty should trigger event'); - await timeout(3); - assert.equal(counter, 3, 'Manual revert should trigger event'); - model.textEditorModel.setValue('foo'); + model.textEditorModel.setValue(''); + return timeout(3).then(() => { + assert.equal(counter, 3, 'Manual revert should trigger event'); - await timeout(3); - assert.equal(counter, 4, 'Dirty model should trigger event'); - model.revert(); + model.textEditorModel.setValue('foo'); + return timeout(3).then(() => { + assert.equal(counter, 4, 'Dirty model should trigger event'); - await timeout(3); - assert.equal(counter, 5, 'Revert should trigger event'); - input.dispose(); + model.revert(); + return timeout(3).then(() => { + assert.equal(counter, 5, 'Revert should trigger event'); + + input.dispose(); + }); + }); + }); + }); + }); + }); }); - test('onDidDisposeModel event', async () => { + test('onDidDisposeModel event', () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -303,9 +288,10 @@ suite('Workbench untitled editors', () => { assert.equal(r.toString(), input.getResource().toString()); }); - await input.resolve(); - assert.equal(counter, 0); - input.dispose(); - assert.equal(counter, 1); + return input.resolve().then(model => { + assert.equal(counter, 0); + input.dispose(); + assert.equal(counter, 1); + }); }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts index 2d084b99dd..9709fb9238 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts @@ -37,7 +37,7 @@ suite('MainThreadSaveParticipant', function () { }); test('insert final new line', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -70,7 +70,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -105,7 +105,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines bug#39750', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -132,7 +132,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines bug#46075', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 844097ffba..7232145354 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -15,7 +15,7 @@ import { ConfirmResult, IEditorInputWithOptions, CloseDirection, IEditorIdentifi import { IEditorOpeningEvent, EditorServiceImpl, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; -import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService, Parts, Position as PartPosition } from 'vs/workbench/services/layout/browser/layoutService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; @@ -85,7 +85,7 @@ import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { BrowserTextFileService } from 'vs/workbench/services/textfile/browser/textFileService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { - return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); + return instantiationService.createInstance(FileEditorInput, resource, undefined); } export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv) as IWindowConfiguration, process.execPath); @@ -1093,7 +1093,7 @@ export class TestBackupFileService implements IBackupFileService { throw new Error('not implemented'); } - public backupResource(_resource: URI, _content: ITextSnapshot, versionId?: number, meta?: T): Promise { + public backupResource(_resource: URI, _content: ITextSnapshot): Promise { return Promise.resolve(); } @@ -1108,7 +1108,7 @@ export class TestBackupFileService implements IBackupFileService { return textBuffer.getValueInRange(range, EndOfLinePreference.TextDefined); } - public resolveBackupContent(_backup: URI): Promise> { + public resolveBackupContent(_backup: URI): Promise { throw new Error('not implemented'); } diff --git a/src/vs/workbench/workbench.web.main.css b/src/vs/workbench/workbench.nodeless.main.css similarity index 100% rename from src/vs/workbench/workbench.web.main.css rename to src/vs/workbench/workbench.nodeless.main.css diff --git a/src/vs/workbench/workbench.web.main.nls.js b/src/vs/workbench/workbench.nodeless.main.nls.js similarity index 100% rename from src/vs/workbench/workbench.web.main.nls.js rename to src/vs/workbench/workbench.nodeless.main.nls.js diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.nodeless.main.ts similarity index 99% rename from src/vs/workbench/workbench.web.main.ts rename to src/vs/workbench/workbench.nodeless.main.ts index 0e4a8d5f5b..540f000684 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.nodeless.main.ts @@ -12,7 +12,7 @@ import 'vs/editor/editor.all'; // import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/browser/workbench.contribution'; -import 'vs/workbench/browser/web.main'; +import 'vs/workbench/browser/nodeless.main'; //#endregion @@ -94,7 +94,7 @@ import { IBroadcastService, NullBroadcastService } from 'vs/workbench/services/b import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import 'vs/workbench/browser/web.simpleservices'; +import 'vs/workbench/browser/nodeless.simpleservices'; import 'vs/platform/dialogs/browser/dialogService'; diff --git a/yarn.lock b/yarn.lock index feea5b4c92..8caf03514d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -832,7 +832,7 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@1.x, async@^1.4.0, async@^1.5.2: +async@1.x, async@^1.4.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= @@ -898,7 +898,7 @@ azure-storage@^2.10.2: xml2js "0.2.8" xmlbuilder "^9.0.7" -babel-code-frame@^6.16.0: +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= @@ -1721,11 +1721,6 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - colors@^1.1.2: version "1.2.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" @@ -1941,11 +1936,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -corser@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= - coveralls@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.3.tgz#83b1c64aea1c6afa69beaf50b55ac1bc4d13e2b8" @@ -2185,13 +2175,6 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -2528,16 +2511,6 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -ecstatic@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.1.tgz#b15b5b036c2233defc78d7bacbd8765226c95577" - integrity sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ== - dependencies: - he "^1.1.1" - mime "^1.6.0" - minimist "^1.1.0" - url-join "^2.0.5" - editions@^1.1.1, editions@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" @@ -2983,11 +2956,6 @@ event-stream@3.3.4, event-stream@^3.3.4, event-stream@~3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -eventemitter3@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -3405,13 +3373,6 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.1" readable-stream "^2.0.4" -follow-redirects@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" - integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== - dependencies: - debug "^3.2.6" - for-in@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.5.tgz#007374e2b6d5c67420a1479bdb75a04872b738c4" @@ -4295,11 +4256,6 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" -he@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4377,29 +4333,6 @@ http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy@^1.8.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== - dependencies: - eventemitter3 "^3.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-server@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" - integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w== - dependencies: - colors "1.0.3" - corser "~2.0.0" - ecstatic "^3.0.0" - http-proxy "^1.8.1" - opener "~1.4.0" - optimist "0.6.x" - portfinder "^1.0.13" - union "~0.4.3" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -4975,11 +4908,6 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - is@^3.1.0, is@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" @@ -5114,7 +5042,7 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.x, js-yaml@^3.5.1: +js-yaml@3.x, js-yaml@^3.5.1, js-yaml@^3.7.0: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" integrity sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA== @@ -5122,7 +5050,7 @@ js-yaml@3.x, js-yaml@^3.5.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.11.0, js-yaml@^3.13.0: +js-yaml@^3.11.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -5845,7 +5773,7 @@ mime@1.4.1, mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.4.1, mime@^1.6.0: +mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -6498,18 +6426,6 @@ oniguruma@^7.0.0: dependencies: nan "^2.10.0" -opener@~1.4.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= - -opn@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - dependencies: - is-wsl "^1.1.0" - optimist@0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.5.tgz#03654b52417030312d109f39b159825b60309304" @@ -6517,7 +6433,7 @@ optimist@0.3.5: dependencies: wordwrap "~0.0.2" -optimist@0.6.x, optimist@^0.6.1: +optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= @@ -6942,15 +6858,6 @@ pluralize@^1.2.1: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU= -portfinder@^1.0.13: - version "1.0.20" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" - integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7407,11 +7314,6 @@ qs@6.5.1, qs@~6.5.1: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== -qs@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" - integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= - qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -7854,11 +7756,6 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -9133,30 +9030,36 @@ tslib@^1.8.1, tslib@^1.9.0: integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tslint-microsoft-contrib@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.1.1.tgz#1de9b5c2867f6cec762bab9d8e1619f2b8eb59fc" - integrity sha512-u6tK+tgt8Z1YRJxe4kpWWEx/6FTFxdga50+osnANifsfC7BMzh8c/t/XbNntTRiwMfpHkQ9xtUjizCDLxN1Yeg== + version "6.0.0" + resolved "https://registry.yarnpkg.com/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.0.0.tgz#7bff73c9ad7a0b7eb5cdb04906de58f42a2bf7a2" + integrity sha512-R//efwn+34IUjTJeYgNDAJdzG0jyLWIehygPt/PHuZAieTolFVS56FgeFW7DOLap9ghXzMiFPTmDgm54qaL7QA== dependencies: tsutils "^2.27.2 <2.29.0" -tslint@^5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.16.0.tgz#ae61f9c5a98d295b9a4f4553b1b1e831c1984d67" - integrity sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA== +tslint@^5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" + integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= dependencies: - "@babel/code-frame" "^7.0.0" + babel-code-frame "^6.22.0" builtin-modules "^1.1.1" chalk "^2.3.0" commander "^2.12.1" diff "^3.2.0" glob "^7.1.1" - js-yaml "^3.13.0" + js-yaml "^3.7.0" minimatch "^3.0.4" - mkdirp "^0.5.1" resolve "^1.3.2" semver "^5.3.0" tslib "^1.8.0" - tsutils "^2.29.0" + tsutils "^2.27.2" + +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" "tsutils@^2.27.2 <2.29.0": version "2.28.0" @@ -9165,13 +9068,6 @@ tslint@^5.16.0: dependencies: tslib "^1.8.1" -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -9370,13 +9266,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -union@~0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" - integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA= - dependencies: - qs "~2.3.3" - uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -9456,11 +9345,6 @@ url-join@^1.1.0: resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg= -url-join@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" - integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= - url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -9856,10 +9740,10 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -vscode-xterm@3.14.0-beta2: - version "3.14.0-beta2" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.14.0-beta2.tgz#5c9e0b9ef72de80f8ba4c9a89cec78cac73bbc1b" - integrity sha512-J/aXupjdOQmHE19tsO8Jrtdv5zMHhluVHBkLdEo2SIZtkkjkhviuwR6vtLotRJX8rcgwcC3z8LbVx0Phi+pvKg== +vscode-xterm@3.13.0-beta3: + version "3.13.0-beta3" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.13.0-beta3.tgz#ab642ed77df07c2adfca7b15ae39c18328db3fc6" + integrity sha512-XvgD/P6CCV0+79UYM7CEL6Ziv2RiDopI3Wa1hIm3Dm8InWxkl3QwykINlempMNub+r0gwVwLKSQYr+Q/jg1IAw== vso-node-api@6.1.2-preview: version "6.1.2-preview"