From 084524cd2dd30a1266f121c86527baf533ac8bf9 Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Mon, 30 Sep 2019 23:35:45 -0700 Subject: [PATCH] Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a (#7436) * Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a * fix strict null checks --- .yarnrc | 2 +- build/monaco/monaco.d.ts.recipe | 2 +- cgmanifest.json | 16 +- extensions/git/src/commands.ts | 2 +- .../client/src/jsonMain.ts | 44 +- .../json-language-features/package.json | 2 +- .../json-language-features/server/README.md | 11 +- .../server/package.json | 4 +- .../server/src/jsonServerMain.ts | 9 +- .../json-language-features/server/yarn.lock | 54 +- extensions/json-language-features/yarn.lock | 48 +- extensions/theme-defaults/themes/dark_vs.json | 3 +- .../theme-defaults/themes/light_vs.json | 3 +- remote/.yarnrc | 2 +- resources/linux/code-url-handler.desktop | 2 +- resources/linux/code.desktop | 4 +- scripts/test-integration.sh | 2 +- scripts/test.sh | 2 +- src/bootstrap.js | 18 +- src/main.js | 7 +- .../browser/enablePreviewFeatures.ts | 12 + .../workbench/common/enablePreviewFeatures.ts | 12 +- .../electron-browser/enablePreviewFeatures.ts | 27 + .../notebook/browser/notebook.contribution.ts | 2 +- .../browser/gettingStarted.contribution.ts} | 4 +- .../gettingStarted.contribution.ts | 13 + src/tsconfig.strictNullChecks.json | 2 +- src/typings/electron.d.ts | 1737 +++++------------ src/vs/base/browser/markdownRenderer.ts | 2 +- src/vs/base/browser/mouseEvent.ts | 60 +- src/vs/base/browser/touch.ts | 10 +- src/vs/base/browser/ui/actionbar/actionbar.ts | 2 +- src/vs/base/browser/ui/button/button.ts | 2 +- src/vs/base/browser/ui/dropdown/dropdown.ts | 2 +- src/vs/base/browser/ui/list/listView.ts | 2 +- src/vs/base/browser/ui/list/listWidget.ts | 2 +- src/vs/base/browser/ui/menu/menu.ts | 2 +- src/vs/base/browser/ui/menu/menubar.ts | 4 +- .../ui/octiconLabel/octicons/octicons.css | 2 +- .../ui/octiconLabel/octicons/octicons.ttf | Bin 35464 -> 35428 bytes src/vs/base/browser/ui/sash/sash.ts | 2 +- src/vs/base/common/htmlContent.ts | 5 +- src/vs/base/common/insane/insane.d.ts | 8 +- src/vs/base/common/insane/insane.js | 18 +- src/vs/base/common/network.ts | 5 +- .../contextmenu/electron-main/contextmenu.ts | 2 +- src/vs/base/parts/tree/browser/treeView.ts | 4 +- .../base/test/common/markdownString.test.ts | 19 + src/vs/base/worker/defaultWorkerFactory.ts | 2 + src/vs/code/electron-main/app.ts | 16 +- src/vs/code/electron-main/auth.ts | 27 +- src/vs/code/electron-main/sharedProcess.ts | 2 +- src/vs/code/electron-main/window.ts | 2 +- src/vs/code/electron-main/windows.ts | 405 +--- .../code/electron-main/windowsStateStorage.ts | 7 + src/vs/code/node/cli.ts | 14 +- src/vs/code/node/windowsFinder.ts | 131 -- .../node/fixtures/no_vscode_folder/file.txt | 0 .../vscode_folder/_vscode/settings.json | 0 .../test/node/fixtures/vscode_folder/file.txt | 0 .../_vscode/settings.json | 0 .../vscode_home_folder/_vscode/settings.json | 1 - .../node/fixtures/vscode_home_folder/file.txt | 0 src/vs/editor/browser/config/configuration.ts | 6 +- .../browser/config/elementSizeObserver.ts | 6 +- .../browser/controller/pointerHandler.ts | 2 +- .../browser/controller/textAreaHandler.ts | 12 + .../browser/viewParts/minimap/minimap.ts | 48 + .../editor/browser/widget/codeEditorWidget.ts | 6 +- src/vs/editor/common/config/editorOptions.ts | 8 + src/vs/editor/common/editorCommon.ts | 2 + src/vs/editor/common/modes.ts | 2 +- src/vs/editor/contrib/folding/folding.ts | 27 +- src/vs/editor/contrib/folding/foldingModel.ts | 20 + src/vs/editor/contrib/hover/hover.css | 2 +- .../editor/contrib/suggest/media/suggest.css | 2 +- .../accessibilityHelp/accessibilityHelp.ts | 4 +- .../browser/standaloneCodeEditor.ts | 8 +- .../standalone/browser/standaloneEditor.ts | 4 +- src/vs/editor/test/browser/testCodeEditor.ts | 2 +- src/vs/monaco.d.ts | 15 +- .../platform/auth/common/authTokenService.ts | 4 +- .../platform/dialogs/electron-main/dialogs.ts | 211 ++ src/vs/platform/dialogs/node/dialogs.ts | 13 + .../electron-main/electronMainService.ts | 49 +- src/vs/platform/electron/node/electron.ts | 12 +- .../electron-main/sharedProcessMainService.ts | 7 +- .../issue/electron-main/issueMainService.ts | 13 +- .../launch/electron-main/launchMainService.ts | 17 +- src/vs/platform/log/common/bufferLog.ts | 6 + src/vs/platform/log/common/fileLogService.ts | 3 +- src/vs/platform/log/common/log.ts | 38 +- src/vs/platform/log/node/loggerService.ts | 2 +- src/vs/platform/log/node/spdlogService.ts | 19 +- .../platform/menubar/electron-main/menubar.ts | 24 +- src/vs/platform/remote/common/tunnel.ts | 2 +- .../appInsightsAppender.test.ts | 3 +- .../userDataSync/common/userDataSync.ts | 6 + .../userDataSync/common/userDataSyncLog.ts | 4 + .../common/userDataSyncService.ts | 27 +- src/vs/platform/windows/common/windows.ts | 10 +- .../platform/windows/electron-main/windows.ts | 37 +- src/vs/platform/windows/node/window.ts | 128 +- .../windows/test/node/window.test.ts} | 20 +- .../platform/workspaces/common/workspaces.ts | 2 +- .../workspacesHistoryMainService.ts | 20 +- .../electron-main/workspacesMainService.ts | 107 +- .../electron-main/workspacesService.ts | 6 +- .../workspacesMainService.test.ts | 3 +- src/vs/vscode.proposed.d.ts | 40 +- .../api/browser/mainThreadLanguageFeatures.ts | 30 +- .../workbench/api/browser/mainThreadWindow.ts | 2 +- src/vs/workbench/api/common/apiCommands.ts | 12 +- .../workbench/api/common/extHost.api.impl.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 47 +- .../api/common/extHostExtensionService.ts | 1 + .../api/common/extHostLanguageFeatures.ts | 24 +- .../api/common/extHostTypeConverters.ts | 18 +- src/vs/workbench/api/common/extHostWebview.ts | 33 +- src/vs/workbench/api/common/extHostWindow.ts | 4 +- src/vs/workbench/api/common/shared/webview.ts | 1 + src/vs/workbench/api/node/extHostCLIServer.ts | 4 +- .../api/node/extHostExtensionService.ts | 1 + .../workbench/api/worker/extHostLogService.ts | 2 + .../browser/actions/textInputActions.ts | 100 + .../browser/actions/windowActions.ts | 4 +- src/vs/workbench/browser/dnd.ts | 2 +- .../browser/parts/editor/editorWidgets.ts | 2 +- .../parts/editor/noTabsTitleControl.ts | 2 +- .../browser/parts/editor/tabsTitleControl.ts | 2 +- .../parts/statusbar/media/statusbarpart.css | 3 +- .../browser/parts/titlebar/menubarControl.ts | 2 +- src/vs/workbench/common/contributions.ts | 12 +- .../contrib/customEditor/browser/commands.ts | 26 +- .../customEditor/browser/customEditors.ts | 2 +- .../debug/browser/media/debugViewlet.css | 3 +- .../browser/extensionTipsService.ts | 42 +- .../browser/extensions.contribution.ts | 6 +- .../extensions/browser/extensionsActions.ts | 8 +- .../extensions/browser/extensionsViews.ts | 12 +- .../browser/media/extensionsViewlet.css | 4 + .../electron-browser/extensionsSlowActions.ts | 2 +- .../runtimeExtensionsEditor.ts | 2 +- .../contrib/files/browser/fileActions.ts | 2 +- .../contrib/files/browser/fileCommands.ts | 8 +- .../files/browser/media/collapse-all-dark.svg | 4 + .../files/browser/media/collapse-all-hc.svg | 4 + .../browser/media/collapse-all-light.svg | 4 + .../files/browser/media/explorerviewlet.css | 13 + .../contrib/files/browser/views/emptyView.ts | 4 + .../contrib/markers/browser/markersPanel.ts | 7 +- .../electron-browser/startupTimings.ts | 6 +- .../browser/media/settingsEditor2.css | 6 +- .../browser/preferences.contribution.ts | 12 +- .../preferences/browser/settingsEditor2.ts | 2 +- .../preferences/browser/settingsTree.ts | 34 +- .../browser/relauncher.contribution.ts | 8 + .../electron-browser/remote.contribution.ts | 2 +- .../contrib/search/browser/searchView.ts | 8 +- .../electron-browser/workspaceStatsService.ts | 4 +- .../tasks/browser/abstractTaskService.ts | 9 - .../tasks/browser/task.contribution.ts | 9 + .../electron-browser/pre/electron-index.js | 9 + .../browser/gettingStarted.contribution.ts | 13 +- .../gettingStarted/browser/telemetryOptOut.ts | 17 +- .../gettingStarted.contribution.ts | 13 + .../electron-browser/telemetryOptOut.ts | 38 + .../welcome/page/browser/welcomePage.ts | 2 +- .../actions/workspaceActions.ts | 2 +- src/vs/workbench/electron-browser/window.ts | 33 +- .../decorations/browser/decorationsService.ts | 3 +- .../browser/abstractFileDialogService.ts | 8 +- .../electron-browser/fileDialogService.ts | 4 +- .../services/extensions/common/rpcProtocol.ts | 18 +- .../extensions/test/node/rpcProtocol.test.ts | 13 + .../host/browser/browserHostService.ts | 50 +- .../workbench/services/host/browser/host.ts | 51 +- .../electron-browser/desktopHostService.ts | 40 +- .../services/remote/node/tunnelService.ts | 12 +- .../browser/browserTextFileService.ts | 4 + .../textfile/browser/textFileService.ts | 8 +- .../textfile/common/textFileEditorModel.ts | 8 +- .../electron-browser/nativeTextFileService.ts | 41 + .../textfile/test/textFileService.test.ts | 8 +- .../timer/electron-browser/timerService.ts | 6 +- .../url/electron-browser/urlService.ts | 14 +- .../workspaces/browser/workspacesService.ts | 2 +- .../workspaceEditingService.ts | 3 +- .../api/extHostWebview.test.ts | 12 +- .../workbench/test/workbenchTestServices.ts | 160 +- src/vs/workbench/workbench.common.main.ts | 2 +- src/vs/workbench/workbench.desktop.main.ts | 5 +- src/vs/workbench/workbench.web.main.ts | 3 + test/electron/index.js | 15 +- test/smoke/package.json | 2 +- test/smoke/yarn.lock | 475 ++++- 196 files changed, 2927 insertions(+), 2547 deletions(-) create mode 100644 src/sql/workbench/browser/enablePreviewFeatures.ts create mode 100644 src/sql/workbench/electron-browser/enablePreviewFeatures.ts rename src/{vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts => sql/workbench/parts/welcome/gettingStarted/browser/gettingStarted.contribution.ts} (79%) create mode 100644 src/sql/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts create mode 100644 src/vs/base/test/common/markdownString.test.ts delete mode 100644 src/vs/code/node/windowsFinder.ts delete mode 100644 src/vs/code/test/node/fixtures/no_vscode_folder/file.txt delete mode 100644 src/vs/code/test/node/fixtures/vscode_folder/_vscode/settings.json delete mode 100644 src/vs/code/test/node/fixtures/vscode_folder/file.txt delete mode 100644 src/vs/code/test/node/fixtures/vscode_folder/nested_vscode_folder/_vscode/settings.json delete mode 100644 src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json delete mode 100644 src/vs/code/test/node/fixtures/vscode_home_folder/file.txt create mode 100644 src/vs/platform/dialogs/electron-main/dialogs.ts rename src/vs/{code/test/node/windowsFinder.test.ts => platform/windows/test/node/window.test.ts} (80%) create mode 100644 src/vs/workbench/browser/actions/textInputActions.ts create mode 100644 src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg create mode 100644 src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg create mode 100644 src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts diff --git a/.yarnrc b/.yarnrc index e49da7f447..ff946c7a25 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "6.0.9" +target "4.2.10" runtime "electron" diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index ad41a725df..b45cc8b620 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -48,7 +48,7 @@ declare namespace monaco.editor { #include(vs/editor/standalone/common/standaloneThemeService): BuiltinTheme, IStandaloneThemeData, IColors #include(vs/editor/common/modes/supports/tokenization): ITokenThemeRule #include(vs/editor/common/services/webWorker): MonacoWebWorker, IWebWorkerOptions -#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor +#include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IStandaloneEditorConstructionOptions, IDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor export interface ICommandHandler { (...args: any[]): void; } diff --git a/cgmanifest.json b/cgmanifest.json index 8e8fc3484f..c16d88b599 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "91f08db83c2ce8c722ddf0911ead8f7c473bedfa" + "commitHash": "c6a08e5368de4352903e702cde750b33239a50ab" } }, "licenseDetail": [ @@ -40,7 +40,7 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "76.0.3809.146" + "version": "69.0.3497.128" }, { "component": { @@ -48,11 +48,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "64219741218aa87e259cf8257596073b8e747f0a" + "commitHash": "8c70b2084ce5f76ea1e3b3c4ccdeee4483fe338b" } }, "isOnlyProductionDependency": true, - "version": "12.4.0" + "version": "10.11.0" }, { "component": { @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "407747b48c47cdeed156a73dde1c47609470c95a" + "commitHash": "4e4c7527c63fcf27dffaeb58bde996b8d859c0ed" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "6.0.9" + "version": "4.2.10" }, { "component": { @@ -98,11 +98,11 @@ "git": { "name": "vscode-octicons-font", "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", - "commitHash": "415cd5b42ab699b6b46c0bf011ada0a2ae50bfb4" + "commitHash": "4cbf2bd35cf0084eabd47d322cc58339fd7743cf" } }, "license": "MIT", - "version": "1.3.1" + "version": "1.3.2" }, { "component": { diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 24afc46b9c..16cdf95b99 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1268,7 +1268,7 @@ export class CommandCenter { if (pick === saveAndCommit) { await Promise.all(documents.map(d => d.save())); - await repository.add(documents.map(d => d.uri)); + await repository.add([]); } else if (pick !== commit) { return false; // do not commit on cancel } diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index 0655fcdbb2..eac6eaefe5 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -10,8 +10,8 @@ import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light'; const localize = nls.loadMessageBundle(); -import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor } from 'vscode'; -import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError } from 'vscode-languageclient'; +import { workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration, Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken, ProviderResult, TextEdit, Range, Disposable } from 'vscode'; +import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; import { hash } from './utils/hash'; @@ -65,6 +65,8 @@ export function activate(context: ExtensionContext) { let toDispose = context.subscriptions; + let rangeFormatting: Disposable | undefined = undefined; + let packageInfo = getPackageInfo(context); telemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); @@ -101,7 +103,8 @@ export function activate(context: ExtensionContext) { // Register the server for json documents documentSelector, initializationOptions: { - handledSchemaProtocols: ['file'] // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client. + handledSchemaProtocols: ['file'], // language server only loads file-URI. Fetching schemas with other protocols ('http'...) are made on the client. + provideFormatter: false // tell the server to not provide formatting capability and ignore the `json.format.enable` setting. }, synchronize: { // Synchronize the setting section 'json' to the server @@ -224,10 +227,13 @@ export function activate(context: ExtensionContext) { extensions.onDidChange(_ => { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); }); + + // manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652. + updateFormatterRegistration(); + toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); + toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration())); }); - - let languageConfiguration: LanguageConfiguration = { wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/, indentationRules: { @@ -237,8 +243,35 @@ export function activate(context: ExtensionContext) { }; languages.setLanguageConfiguration('json', languageConfiguration); languages.setLanguageConfiguration('jsonc', languageConfiguration); + + function updateFormatterRegistration() { + const formatEnabled = workspace.getConfiguration().get('json.format.enable'); + if (!formatEnabled && rangeFormatting) { + rangeFormatting.dispose(); + rangeFormatting = undefined; + } else if (formatEnabled && !rangeFormatting) { + rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, { + provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult { + let params: DocumentRangeFormattingParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + range: client.code2ProtocolConverter.asRange(range), + options: client.code2ProtocolConverter.asFormattingOptions(options) + }; + return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( + client.protocol2CodeConverter.asTextEdits, + (error) => { + client.logFailedRequest(DocumentRangeFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + }); + } + } } + + export function deactivate(): Promise { return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null); } @@ -286,7 +319,6 @@ function getSettings(): Settings { proxyStrictSSL: httpSettings.get('proxyStrictSSL') }, json: { - format: workspace.getConfiguration('json').get('format'), schemas: [], } }; diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 167583302c..cc61c9163c 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -104,7 +104,7 @@ "dependencies": { "request-light": "^0.2.4", "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.3.0-next.6", + "vscode-languageclient": "^6.0.0-next.1", "vscode-nls": "^4.1.1" }, "devDependencies": { diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md index 5ca997d9e1..dbc72d1460 100644 --- a/extensions/json-language-features/server/README.md +++ b/extensions/json-language-features/server/README.md @@ -12,7 +12,7 @@ The JSON Language server provides language-specific smarts for editing, validati The JSON language server supports requests on documents of language id `json` and `jsonc`. - `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159). -- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`) and accepts trailing commas. JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format. +- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`). JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format. The server implements the following capabilities of the language server protocol: @@ -40,6 +40,13 @@ The JSON language server has the following dependencies on the client's capabili ## Configuration +### Initialization options + +The client can send the following initialization options to the server: + +- `provideFormatter: boolean | undefined`. If defined, the value defines wheter the server provides the `documentRangeFormattingProvider` capability on initialization. If undefined, the setting `json.format.enable` is used to determined wheter formatting is provided. The formatter will then be registered through dynamic registration. If the client does not support dynamic registration, no formatter will be available. +- `handledSchemaProtocols`: The URI schemas handles by the server. See section `Schema configuration` below. + ### Settings Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes. @@ -51,7 +58,7 @@ The server supports the following settings: - json - `format` - - `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* + - `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined. - `schema`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content. - `fileMatch`: an array or file names or paths (separated by `/`). `*` can be used as a wildcard. - `url`: The URL of the schema, optional when also a schema is provided. diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 28c4648325..3559b36e9a 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,8 +14,8 @@ "dependencies": { "jsonc-parser": "^2.1.1", "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.3.4", - "vscode-languageserver": "^5.3.0-next.8", + "vscode-json-languageservice": "^3.3.5", + "vscode-languageserver": "^6.0.0-next.1", "vscode-nls": "^4.1.1", "vscode-uri": "^2.0.3" }, diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 52d6579e01..f96284b56d 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -114,7 +114,7 @@ const documents: TextDocuments = new TextDocuments(); documents.listen(connection); let clientSnippetSupport = false; -let clientDynamicRegisterSupport = false; +let dynamicFormatterRegistration = false; let foldingRangeLimit = Number.MAX_VALUE; let hierarchicalDocumentSymbolSupport = false; @@ -144,7 +144,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { } clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false); - clientDynamicRegisterSupport = getClientCapability('workspace.symbol.dynamicRegistration', false); + dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (params.initializationOptions.provideFormatter === undefined); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false); const capabilities: ServerCapabilities = { @@ -156,7 +156,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { documentRangeFormattingProvider: false, colorProvider: {}, foldingRangeProvider: true, - selectionRangeProvider: true + selectionRangeProvider: true, + documentFormattingProvider: params.initializationOptions.provideFormatter === true }; return { capabilities }; @@ -195,7 +196,7 @@ connection.onDidChangeConfiguration((change) => { updateConfiguration(); // dynamically enable & disable the formatter - if (clientDynamicRegisterSupport) { + if (dynamicFormatterRegistration) { const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable; if (enableFormatter) { if (!formatterRegistration) { diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 8230b9546b..0ceb7ddcb1 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -73,42 +73,41 @@ request-light@^0.2.4: https-proxy-agent "^2.2.1" vscode-nls "^4.0.0" -vscode-json-languageservice@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.4.tgz#4ff67580491d3a5dc469f4a78643f20adff0278d" - integrity sha512-/nuI4uDBfxyVyeGtBdYwP/tIaXYKOoymUOSozYKLzsmrDmu555gZpzc11LrARa96z92wSaa5hfjTtNMAoM2mxw== +vscode-json-languageservice@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.5.tgz#e222e8391beeb23cfa40cf17fd57d1594d295fc7" + integrity sha512-Le6SG5aRdrRc5jVeVMRkYbGH9rrVaZHCW0Oa8zCFQ0T8viUud9qdZ29lSv5NPNLwTB8mn4pYucFyyEPM2YWvLA== dependencies: jsonc-parser "^2.1.1" - vscode-languageserver-types "^3.15.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" vscode-nls "^4.1.1" vscode-uri "^2.0.3" -vscode-jsonrpc@^4.1.0-next.2: - version "4.1.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3" - integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg== +vscode-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -vscode-languageserver-protocol@^3.15.0-next.6: - version "3.15.0-next.6" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92" - integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -vscode-languageserver-types@^3.15.0-next.2: - version "3.15.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254" - integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ== +vscode-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== -vscode-languageserver@^5.3.0-next.8: - version "5.3.0-next.8" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.8.tgz#12a4adf60374dbb93e153e08bdca5525f9b2029f" - integrity sha512-6vUb96wsRfrFqndril3gct/FBCSc24OxFZ2iz7kuEuXvLaIcEVOcSZIqQK8oFN7PdbAIaa9nnIpKSy4Yd15cIw== +vscode-languageserver@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-6.0.0-next.1.tgz#4d71886d4a17d22eafc61b3a5fbf84e8e27c191f" + integrity sha512-LSF6bXoFeXfMPRNyqzI3yFX/kD2DzXBemqvyj1kDWNVraiWttm4xKF4YXsvJ7Z3s9sVt/Dpu3CFU3w61PGNZMg== dependencies: - vscode-languageserver-protocol "^3.15.0-next.6" + vscode-languageserver-protocol "^3.15.0-next.9" vscode-textbuffer "^1.0.0" - vscode-uri "^1.0.6" vscode-nls@^4.0.0: version "4.0.0" @@ -125,11 +124,6 @@ vscode-textbuffer@^1.0.0: resolved "https://registry.yarnpkg.com/vscode-textbuffer/-/vscode-textbuffer-1.0.0.tgz#1faee638c8e0e4131c8d5c353993a1874acda086" integrity sha512-zPaHo4urgpwsm+PrJWfNakolRpryNja18SUip/qIIsfhuEqEIPEXMxHOlFPjvDC4JgTaimkncNW7UMXRJTY6ow== -vscode-uri@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" - integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== - vscode-uri@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index fdc89dd7cf..b3804735a7 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -101,10 +101,10 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -semver@^5.5.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== vscode-extension-telemetry@0.1.1: version "0.1.1" @@ -113,31 +113,31 @@ vscode-extension-telemetry@0.1.1: dependencies: applicationinsights "1.0.8" -vscode-jsonrpc@^4.1.0-next.2: - version "4.1.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3" - integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg== +vscode-jsonrpc@^5.0.0-next.2: + version "5.0.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.2.tgz#a44bc03f67069e53f8d8beb88b96c0cacbfefbca" + integrity sha512-Q3/jabZUNviCG9hhF6hHWjhrABevPF9mv0aiE2j8BYCAP2k+aHTpjMyk+04MzaAqWYwXdQuZkLSbcYCCqbzJLg== -vscode-languageclient@^5.3.0-next.6: - version "5.3.0-next.6" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.3.0-next.6.tgz#35e74882781158e8b111911c0953869d3df08777" - integrity sha512-DxT8+gkenjCjJV6ArcP75/AQfx6HP6m6kHIbacPCpffMeoE1YMLKj6ZixA9J87yr0fMtBmqumLmDeGe7MIF2bw== +vscode-languageclient@^6.0.0-next.1: + version "6.0.0-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.0.0-next.1.tgz#deca1743afd20da092e04e40ef73cedbbd978455" + integrity sha512-eJ9VjLFNINArgRzLbQ11YlWry7dM93GEODkQBXTRfrSypksiO9qSGr4SHhWgxxP26p4FRSpzc/17+N+Egnnchg== dependencies: - semver "^5.5.0" - vscode-languageserver-protocol "^3.15.0-next.6" + semver "^6.3.0" + vscode-languageserver-protocol "^3.15.0-next.9" -vscode-languageserver-protocol@^3.15.0-next.6: - version "3.15.0-next.6" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92" - integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ== +vscode-languageserver-protocol@^3.15.0-next.9: + version "3.15.0-next.9" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.9.tgz#e768256bd5b580b25bfbc8099bc03bc4c42ebf30" + integrity sha512-b9PAxouMmtsLEe8ZjbIMPb7wRWPhckGfgjwZLmp/dWnaAuRPYtY3lGO0/rNbLc3jKIqCVlnEyYVFKalzDAzj0g== dependencies: - vscode-jsonrpc "^4.1.0-next.2" - vscode-languageserver-types "^3.15.0-next.2" + vscode-jsonrpc "^5.0.0-next.2" + vscode-languageserver-types "^3.15.0-next.5" -vscode-languageserver-types@^3.15.0-next.2: - version "3.15.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254" - integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ== +vscode-languageserver-types@^3.15.0-next.5: + version "3.15.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.5.tgz#863d711bf47b338ff5e63ae19fb20d4fcd4d713b" + integrity sha512-7hrELhTeWieUgex3+6692KjCkcmO/+V/bFItM5MHGcBotzwmjEuXjapLLYTYhIspuJ1ibRSik5MhX5YwLpsPiw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/theme-defaults/themes/dark_vs.json b/extensions/theme-defaults/themes/dark_vs.json index 34228835df..fe0f8fc889 100644 --- a/extensions/theme-defaults/themes/dark_vs.json +++ b/extensions/theme-defaults/themes/dark_vs.json @@ -171,8 +171,7 @@ }, { "scope": [ - "meta.preprocessor", - "keyword.control.directive" + "meta.preprocessor" ], "settings": { "foreground": "#569cd6" diff --git a/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json index 96cb7a76fa..74bd28d245 100644 --- a/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -169,8 +169,7 @@ }, { "scope": [ - "meta.preprocessor", - "keyword.control.directive" + "meta.preprocessor" ], "settings": { "foreground": "#0000ff" diff --git a/remote/.yarnrc b/remote/.yarnrc index 1e16cde724..b28191e6ba 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,3 +1,3 @@ disturl "http://nodejs.org/dist" -target "12.4.0" +target "10.11.0" runtime "node" diff --git a/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop index caf34337a3..b8e921920b 100644 --- a/resources/linux/code-url-handler.desktop +++ b/resources/linux/code-url-handler.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ - URL Handler Comment=Azure Data Studio GenericName=Text Editor -Exec=@@EXEC@@ --no-sandbox --open-url %U +Exec=@@EXEC@@ --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 53ad8dc607..3940900ed6 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Data Management Tool that enables you to work with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux. GenericName=Text Editor -Exec=@@EXEC@@ --no-sandbox --unity-launch %F +Exec=@@EXEC@@ --unity-launch %F Icon=@@ICON@@ Type=Application StartupNotify=false @@ -14,5 +14,5 @@ Keywords=azuredatastudio; [Desktop Action new-empty-window] Name=New Empty Window -Exec=@@EXEC@@ --no-sandbox --new-window %F +Exec=@@EXEC@@ --new-window %F Icon=@@ICON@@ diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 42a14cd2a3..6911d68021 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -8,7 +8,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then else ROOT=$(dirname $(dirname $(readlink -f $0))) VSCODEUSERDATADIR=`mktemp -d 2>/dev/null` - LINUX_NO_SANDBOX="--no-sandbox" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. + LINUX_NO_SANDBOX="" fi cd $ROOT diff --git a/scripts/test.sh b/scripts/test.sh index ac09157151..9b6a3b86b8 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -34,5 +34,5 @@ else cd $ROOT ; \ ELECTRON_ENABLE_LOGGING=1 \ "$CODE" \ - test/electron/index.js --no-sandbox "$@" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. + test/electron/index.js "$@" fi diff --git a/src/bootstrap.js b/src/bootstrap.js index 8a6a02ab5a..8d95ffee95 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -21,7 +21,6 @@ process.on('SIGPIPE', () => { //#endregion //#region Add support for redirecting the loading of node modules - exports.injectNodeModuleLookupPath = function (injectPath) { if (!injectPath) { throw new Error('Missing injectPath'); @@ -37,8 +36,10 @@ exports.injectNodeModuleLookupPath = function (injectPath) { const originalResolveLookupPaths = Module._resolveLookupPaths; // @ts-ignore - Module._resolveLookupPaths = function (moduleName, parent) { - const paths = originalResolveLookupPaths(moduleName, parent); + Module._resolveLookupPaths = function (moduleName, parent, newReturn) { + const result = originalResolveLookupPaths(moduleName, parent, newReturn); + + const paths = newReturn ? result : result[1]; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === nodeModulesPath) { paths.splice(i, 0, injectPath); @@ -46,7 +47,7 @@ exports.injectNodeModuleLookupPath = function (injectPath) { } } - return paths; + return result; }; }; //#endregion @@ -70,10 +71,11 @@ exports.enableASARSupport = function (nodeModulesPath) { // @ts-ignore const originalResolveLookupPaths = Module._resolveLookupPaths; - // @ts-ignore - Module._resolveLookupPaths = function (request, parent) { - const paths = originalResolveLookupPaths(request, parent); + Module._resolveLookupPaths = function (request, parent, newReturn) { + const result = originalResolveLookupPaths(request, parent, newReturn); + + const paths = newReturn ? result : result[1]; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === NODE_MODULES_PATH) { paths.splice(i, 0, NODE_MODULES_ASAR_PATH); @@ -81,7 +83,7 @@ exports.enableASARSupport = function (nodeModulesPath) { } } - return paths; + return result; }; }; //#endregion diff --git a/src/main.js b/src/main.js index 1059583cd4..4fba3a2672 100644 --- a/src/main.js +++ b/src/main.js @@ -17,7 +17,7 @@ const paths = require('./paths'); // @ts-ignore const product = require('../product.json'); // @ts-ignore -const { app, protocol } = require('electron'); +const app = require('electron').app; // Enable portable support const portable = bootstrap.configurePortable(); @@ -33,11 +33,6 @@ app.setPath('userData', userDataPath); // Update cwd based on environment and platform setCurrentWorkingDirectory(); -// Register custom schemes with privileges -protocol.registerSchemesAsPrivileged([ - { scheme: 'vscode-resource', privileges: { secure: true, supportFetchAPI: true, corsEnabled: true } } -]); - // Global app listeners registerListeners(); diff --git a/src/sql/workbench/browser/enablePreviewFeatures.ts b/src/sql/workbench/browser/enablePreviewFeatures.ts new file mode 100644 index 0000000000..70f3da65ee --- /dev/null +++ b/src/sql/workbench/browser/enablePreviewFeatures.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures'; + +export class BrowserEnablePreviewFeatures extends AbstractEnablePreviewFeatures { + protected async getWindowCount(): Promise { + return 1; + } +} diff --git a/src/sql/workbench/common/enablePreviewFeatures.ts b/src/sql/workbench/common/enablePreviewFeatures.ts index f384ed638a..3f3d9122fa 100644 --- a/src/sql/workbench/common/enablePreviewFeatures.ts +++ b/src/sql/workbench/common/enablePreviewFeatures.ts @@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class EnablePreviewFeatures implements IWorkbenchContribution { +export abstract class AbstractEnablePreviewFeatures implements IWorkbenchContribution { private static ENABLE_PREVIEW_FEATURES_SHOWN = 'workbench.enablePreviewFeaturesShown'; @@ -22,12 +22,12 @@ export class EnablePreviewFeatures implements IWorkbenchContribution { @IConfigurationService configurationService: IConfigurationService ) { let previewFeaturesEnabled = configurationService.getValue('workbench')['enablePreviewFeatures']; - if (previewFeaturesEnabled || storageService.get(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) { + if (previewFeaturesEnabled || storageService.get(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) { return; } Promise.all([ hostService.hasFocus, - hostService.windowCount + this.getWindowCount() ]).then(([focused, count]) => { if (!focused && count > 1) { return null; @@ -42,7 +42,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution { label: localize('enablePreviewFeatures.yes', "Yes"), run: () => { configurationService.updateValue('workbench.enablePreviewFeatures', true); - storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL); + storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL); } }, { label: localize('enablePreviewFeatures.no', "No"), @@ -53,7 +53,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution { label: localize('enablePreviewFeatures.never', "No, don't show again"), run: () => { configurationService.updateValue('workbench.enablePreviewFeatures', false); - storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL); + storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL); }, isSecondary: true }] @@ -61,4 +61,6 @@ export class EnablePreviewFeatures implements IWorkbenchContribution { }) .then(null, onUnexpectedError); } + + protected abstract getWindowCount(): Promise; } diff --git a/src/sql/workbench/electron-browser/enablePreviewFeatures.ts b/src/sql/workbench/electron-browser/enablePreviewFeatures.ts new file mode 100644 index 0000000000..3c83b3f255 --- /dev/null +++ b/src/sql/workbench/electron-browser/enablePreviewFeatures.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +export class NativeEnablePreviewFeatures extends AbstractEnablePreviewFeatures { + + constructor( + @IStorageService storageService: IStorageService, + @INotificationService notificationService: INotificationService, + @IHostService hostService: IHostService, + @IConfigurationService configurationService: IConfigurationService, + @IElectronService private readonly electronService: IElectronService + ) { + super(storageService, notificationService, hostService, configurationService); + } + protected getWindowCount(): Promise { + return this.electronService.getWindowCount(); + } +} diff --git a/src/sql/workbench/parts/notebook/browser/notebook.contribution.ts b/src/sql/workbench/parts/notebook/browser/notebook.contribution.ts index 02816baea8..fb0fc55f33 100644 --- a/src/sql/workbench/parts/notebook/browser/notebook.contribution.ts +++ b/src/sql/workbench/parts/notebook/browser/notebook.contribution.ts @@ -138,7 +138,7 @@ registerAction({ await workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder }))); await viewletService.openViewlet(viewletService.getDefaultViewletId(), true); if (options.forceNewWindow) { - return hostService.openInWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow }); + return hostService.openWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow }); } else { return hostService.reload(); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts b/src/sql/workbench/parts/welcome/gettingStarted/browser/gettingStarted.contribution.ts similarity index 79% rename from src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts rename to src/sql/workbench/parts/welcome/gettingStarted/browser/gettingStarted.contribution.ts index a25d14b701..1e4c417821 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution.ts +++ b/src/sql/workbench/parts/welcome/gettingStarted/browser/gettingStarted.contribution.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { OpenWelcomePageInBrowser } from './openWebsite'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { BrowserEnablePreviewFeatures } from 'sql/workbench/browser/enablePreviewFeatures'; Registry .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(OpenWelcomePageInBrowser, LifecyclePhase.Restored); + .registerWorkbenchContribution(BrowserEnablePreviewFeatures, LifecyclePhase.Eventually); diff --git a/src/sql/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts b/src/sql/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts new file mode 100644 index 0000000000..450ed4de3e --- /dev/null +++ b/src/sql/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { NativeEnablePreviewFeatures } from 'sql/workbench/electron-browser/enablePreviewFeatures'; + +Registry + .as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(NativeEnablePreviewFeatures, LifecyclePhase.Eventually); diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 0b8f9dba7b..28d1fd5abf 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -14,7 +14,7 @@ "./sql/azdata.d.ts", "./sql/azdata.proposed.d.ts", "./vs/base/**/*.ts", - "./vs/platform/**/*.ts", + // "./vs/platform/**/*.ts", "./sql/base/**/*.ts", "./sql/editor/**/*.ts", "./sql/platform/angularEventing/**/*.ts", diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 3e55cdc4bf..6f44785756 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 6.0.9 +// Type definitions for Electron 4.2.10 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -8,7 +8,6 @@ type GlobalEvent = Event; declare namespace Electron { - // TODO: Replace this declaration with NodeJS.EventEmitter class EventEmitter { addListener(event: string, listener: Function): this; on(event: string, listener: Function): this; @@ -22,17 +21,28 @@ declare namespace Electron { listenerCount(type: string): number; prependListener(event: string, listener: Function): this; prependOnceListener(event: string, listener: Function): this; - eventNames(): Array<(string | symbol)>; + eventNames(): string[]; } class Accelerator extends String { } + interface Event extends GlobalEvent { + preventDefault: () => void; + sender: WebContents; + returnValue: any; + ctrlKey?: boolean; + metaKey?: boolean; + shiftKey?: boolean; + altKey?: boolean; + } + interface CommonInterface { clipboard: Clipboard; crashReporter: CrashReporter; nativeImage: typeof NativeImage; + screen: Screen; shell: Shell; } @@ -59,7 +69,6 @@ declare namespace Electron { powerMonitor: PowerMonitor; powerSaveBlocker: PowerSaveBlocker; protocol: Protocol; - screen: Screen; session: typeof Session; systemPreferences: SystemPreferences; TouchBar: typeof TouchBar; @@ -194,9 +203,9 @@ declare namespace Electron { userInfo: any) => void): this; /** * Emitted before the application starts closing its windows. Calling - * event.preventDefault() will prevent the default behavior, which is terminating + * event.preventDefault() will prevent the default behaviour, which is terminating * the application. Note: If application quit was initiated by - * autoUpdater.quitAndInstall(), then before-quit is emitted after emitting close + * autoUpdater.quitAndInstall() then before-quit is emitted after emitting close * event on all windows and closing them. Note: On Windows, this event will not be * emitted if the app is closed due to a shutdown/restart of the system or a user * logout. @@ -363,18 +372,6 @@ declare namespace Electron { * A string with the error's localized description. */ error: string) => void): this; - /** - * Emitted when desktopCapturer.getSources() is called in the renderer process of - * webContents. Calling event.preventDefault() will make it return empty sources. - */ - on(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; /** * Emitted when the gpu process crashes or is killed. */ @@ -388,7 +385,7 @@ declare namespace Electron { killed: boolean) => void): this; /** * Emitted when webContents wants to do basic auth. The default behavior is to - * cancel all authentications. To override this you should prevent the default + * cancel all authentications, to override this you should prevent the default * behavior with event.preventDefault() and call callback(username, password) with * the credentials. */ @@ -569,30 +566,13 @@ declare namespace Electron { removeListener(event: 'remote-require', listener: (event: Event, webContents: WebContents, moduleName: string) => void): this; - /** - * Emitted when the renderer process of webContents crashes or is killed. - */ - on(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - once(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - addListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - removeListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; /** * This event will be emitted inside the primary instance of your application when - * a second instance has been executed and calls app.requestSingleInstanceLock(). - * argv is an Array of the second instance's command line arguments, and - * workingDirectory is its current working directory. Usually applications respond - * to this by making their primary window focused and non-minimized. This event is - * guaranteed to be emitted after the ready event of app gets emitted. Note: Extra - * command line arguments might be added by Chromium, such as - * --original-process-start-time. + * a second instance has been executed. argv is an Array of the second instance's + * command line arguments, and workingDirectory is its current working directory. + * Usually applications respond to this by making their primary window focused and + * non-minimized. This event is guaranteed to be emitted after the ready event of + * app gets emitted. */ on(event: 'second-instance', listener: (event: Event, /** @@ -667,8 +647,8 @@ declare namespace Electron { * Emitted when Handoff is about to be resumed on another device. If you need to * update the state to be transferred, you should call event.preventDefault() * immediately, construct a new userInfo dictionary and call - * app.updateCurrentActiviy() in a timely manner. Otherwise, the operation will - * fail and continue-activity-error will be called. + * app.updateCurrentActiviy() in a timely manner. Otherwise the operation will fail + * and continue-activity-error will be called. */ on(event: 'update-activity-state', listener: (event: Event, /** @@ -780,8 +760,8 @@ declare namespace Electron { removeListener(event: 'window-all-closed', listener: Function): this; /** * Adds path to the recent documents list. This list is managed by the OS. On - * Windows, you can visit the list from the task bar, and on macOS, you can visit - * it from dock menu. + * Windows you can visit the list from the task bar, and on macOS you can visit it + * from dock menu. */ addRecentDocument(path: string): void; /** @@ -799,6 +779,11 @@ declare namespace Electron { * before app is ready. */ disableHardwareAcceleration(): void; + /** + * Enables mixed sandbox mode on the app. This method can only be called before app + * is ready. + */ + enableMixedSandbox(): void; /** * Enables full sandbox mode on the app. This method can only be called before app * is ready. @@ -806,8 +791,8 @@ declare namespace Electron { enableSandbox(): void; /** * Exits immediately with exitCode. exitCode defaults to 0. All windows will be - * closed immediately without asking the user, and the before-quit and will-quit - * events will not be emitted. + * closed immediately without asking user and the before-quit and will-quit events + * will not be emitted. */ exit(exitCode?: number): void; /** @@ -823,19 +808,12 @@ declare namespace Electron { * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux * and macOS, icons depend on the application associated with file mime type. */ - getFileIcon(path: string, options?: FileIconOptions): Promise; + getFileIcon(path: string, callback: (error: Error, icon: NativeImage) => void): void; /** - * Fetches a path's associated icon. On Windows, there are 2 kinds of icons: On - * Linux and macOS, icons depend on the application associated with file mime type. - * Deprecated Soon + * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux + * and macOS, icons depend on the application associated with file mime type. */ getFileIcon(path: string, options: FileIconOptions, callback: (error: Error, icon: NativeImage) => void): void; - /** - * Fetches a path's associated icon. On Windows, there are 2 kinds of icons: On - * Linux and macOS, icons depend on the application associated with file mime type. - * Deprecated Soon - */ - getFileIcon(path: string, callback: (error: Error, icon: NativeImage) => void): void; getGPUFeatureStatus(): GPUFeatureStatus; /** * For infoType equal to complete: Promise is fulfilled with Object containing all @@ -850,16 +828,12 @@ declare namespace Electron { /** * To set the locale, you'll want to use a command line switch at app startup, * which may be found here. Note: When distributing your packaged app, you have to - * also ship the locales folder. Note: On Windows, you have to call it after the + * also ship the locales folder. Note: On Windows you have to call it after the * ready events gets emitted. */ getLocale(): string; /** - * Note: When unable to detect locale country code, it returns empty string. - */ - getLocaleCountryCode(): string; - /** - * If you provided path and args options to app.setLoginItemSettings, then you need + * If you provided path and args options to app.setLoginItemSettings then you need * to pass the same arguments here for openAtLogin to be set correctly. */ getLoginItemSettings(options?: LoginItemSettingsOptions): LoginItemSettings; @@ -896,9 +870,6 @@ declare namespace Electron { * Invalidates the current Handoff user activity. */ invalidateCurrentActivity(type: string): void; - /** - * Deprecated Soon - */ isAccessibilitySupportEnabled(): boolean; /** * This method checks if the current executable is the default handler for a @@ -910,16 +881,15 @@ declare namespace Electron { * the Windows Registry and LSCopyDefaultHandlerForURLScheme internally. */ isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - isEmojiPanelSupported(): boolean; isInApplicationsFolder(): boolean; isReady(): boolean; isUnityRunning(): boolean; /** - * No confirmation dialog will be presented by default. If you wish to allow the - * user to confirm the operation, you may do so using the dialog API. NOTE: This + * No confirmation dialog will be presented by default, if you wish to allow the + * user to confirm the operation you may do so using the dialog API. NOTE: This * method throws errors if anything other than the user causes the move to fail. - * For instance if the user cancels the authorization dialog, this method returns - * false. If we fail to perform the copy, then this method will throw an error. The + * For instance if the user cancels the authorization dialog this method returns + * false. If we fail to perform the copy then this method will throw an error. The * message in the error should be informative and tell you exactly what went wrong */ moveToApplicationsFolder(): boolean; @@ -933,14 +903,14 @@ declare namespace Electron { */ quit(): void; /** - * Relaunches the app when current instance exits. By default, the new instance - * will use the same working directory and command line arguments with current - * instance. When args is specified, the args will be passed as command line - * arguments instead. When execPath is specified, the execPath will be executed for - * relaunch instead of current app. Note that this method does not quit the app - * when executed, you have to call app.quit or app.exit after calling app.relaunch - * to make the app restart. When app.relaunch is called for multiple times, - * multiple instances will be started after current instance exited. An example of + * Relaunches the app when current instance exits. By default the new instance will + * use the same working directory and command line arguments with current instance. + * When args is specified, the args will be passed as command line arguments + * instead. When execPath is specified, the execPath will be executed for relaunch + * instead of current app. Note that this method does not quit the app when + * executed, you have to call app.quit or app.exit after calling app.relaunch to + * make the app restart. When app.relaunch is called for multiple times, multiple + * instances will be started after current instance exited. An example of * restarting current instance immediately and adding a new command line argument * to the new instance: */ @@ -956,25 +926,27 @@ declare namespace Electron { */ removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; /** - * The return value of this method indicates whether or not this instance of your - * application successfully obtained the lock. If it failed to obtain the lock, - * you can assume that another instance of your application is already running with - * the lock and exit immediately. I.e. This method returns true if your process is - * the primary instance of your application and your app should continue loading. - * It returns false if your process should immediately quit as it has sent its - * parameters to another instance that has already acquired the lock. On macOS, the - * system enforces single instance automatically when users try to open a second - * instance of your app in Finder, and the open-file and open-url events will be - * emitted for that. However when users start your app in command line, the - * system's single instance mechanism will be bypassed, and you have to use this + * This method makes your application a Single Instance Application - instead of + * allowing multiple instances of your app to run, this will ensure that only a + * single instance of your app is running, and other instances signal this instance + * and exit. The return value of this method indicates whether or not this instance + * of your application successfully obtained the lock. If it failed to obtain the + * lock you can assume that another instance of your application is already running + * with the lock and exit immediately. I.e. This method returns true if your + * process is the primary instance of your application and your app should continue + * loading. It returns false if your process should immediately quit as it has + * sent its parameters to another instance that has already acquired the lock. On + * macOS the system enforces single instance automatically when users try to open a + * second instance of your app in Finder, and the open-file and open-url events + * will be emitted for that. However when users start your app in command line the + * system's single instance mechanism will be bypassed and you have to use this * method to ensure single instance. An example of activating the window of primary * instance when a second instance starts: */ requestSingleInstanceLock(): boolean; /** * Set the about panel options. This will override the values defined in the app's - * .plist file on MacOS. See the Apple docs for more details. On Linux, values must - * be set in order to be shown; there are no defaults. + * .plist file. See the Apple docs for more details. */ setAboutPanelOptions(options: AboutPanelOptionsOptions): void; /** @@ -983,17 +955,9 @@ declare namespace Electron { * accessibility docs for more details. Disabled by default. This API must be * called after the ready event is emitted. Note: Rendering accessibility tree can * significantly affect the performance of your app. It should not be enabled by - * default. Deprecated Soon + * default. */ setAccessibilitySupportEnabled(enabled: boolean): void; - /** - * Sets or creates a directory your app's logs which can then be manipulated with - * app.getPath() or app.setPath(pathName, newPath). Calling app.setAppLogsPath() - * without a path parameter will result in this directory being set to - * /Library/Logs/YourAppName on macOS, and inside the userData directory on Linux - * and Windows. - */ - setAppLogsPath(path?: string): void; /** * Changes the Application User Model ID to id. */ @@ -1003,23 +967,20 @@ declare namespace Electron { * (aka URI scheme). It allows you to integrate your app deeper into the operating * system. Once registered, all links with your-protocol:// will be opened with the * current executable. The whole link, including protocol, will be passed to your - * application as a parameter. On Windows, you can provide optional parameters - * path, the path to your executable, and args, an array of arguments to be passed - * to your executable when it launches. Note: On macOS, you can only register + * application as a parameter. On Windows you can provide optional parameters path, + * the path to your executable, and args, an array of arguments to be passed to + * your executable when it launches. Note: On macOS, you can only register * protocols that have been added to your app's info.plist, which can not be * modified at runtime. You can however change the file with a simple text editor * or script during build time. Please refer to Apple's documentation for details. - * Note: In a Windows Store environment (when packaged as an appx) this API will - * return true for all calls but the registry key it sets won't be accessible by - * other applications. In order to register your Windows Store application as a - * default protocol handler you must declare the protocol in your manifest. The API - * uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally. + * The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme + * internally. */ setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; /** * Sets the counter badge for current app. Setting the count to 0 will hide the - * badge. On macOS, it shows on the dock icon. On Linux, it only works for Unity - * launcher. Note: Unity launcher requires the existence of a .desktop file to + * badge. On macOS it shows on the dock icon. On Linux it only works for Unity + * launcher, Note: Unity launcher requires the existence of a .desktop file to * work, for more information please read Desktop Environment Integration. */ setBadgeCount(count: number): boolean; @@ -1051,12 +1012,12 @@ declare namespace Electron { setName(name: string): void; /** * Overrides the path to a special directory or file associated with name. If the - * path specifies a directory that does not exist, an Error is thrown. In that - * case, the directory should be created with fs.mkdirSync or similar. You can only - * override paths of a name defined in app.getPath. By default, web pages' cookies - * and caches will be stored under the userData directory. If you want to change - * this location, you have to override the userData path before the ready event of - * the app module is emitted. + * path specifies a directory that does not exist, the directory will be created by + * this method. On failure an Error is thrown. You can only override paths of a + * name defined in app.getPath. By default, web pages' cookies and caches will be + * stored under the userData directory. If you want to change this location, you + * have to override the userData path before the ready event of the app module is + * emitted. */ setPath(name: string, path: string): void; /** @@ -1076,14 +1037,10 @@ declare namespace Electron { */ show(): void; /** - * Show the app's about panel options. These options can be overridden with - * app.setAboutPanelOptions(options). + * Show the about panel with the values defined in the app's .plist file or with + * the options set via app.setAboutPanelOptions(options). */ showAboutPanel(): void; - /** - * Show the platform's native emoji picker. - */ - showEmojiPanel(): void; /** * Start accessing a security scoped resource. With this method Electron * applications that are packaged for the Mac App Store may reach outside their @@ -1097,34 +1054,6 @@ declare namespace Electron { */ updateCurrentActivity(type: string, userInfo: any): void; whenReady(): Promise; - /** - * A Boolean property that's true if Chrome's accessibility support is enabled, - * false otherwise. This property will be true if the use of assistive - * technologies, such as screen readers, has been detected. Setting this property - * to true manually enables Chrome's accessibility support, allowing developers to - * expose accessibility switch to users in application settings. See Chromium's - * accessibility docs for more details. Disabled by default. This API must be - * called after the ready event is emitted. Note: Rendering accessibility tree can - * significantly affect the performance of your app. It should not be enabled by - * default. - */ - accessibilitySupportEnabled?: boolean; - /** - * A Boolean which when true disables the overrides that Electron has in place to - * ensure renderer processes are restarted on every navigation. The current - * default value for this property is false. The intention is for these overrides - * to become disabled by default and then at some point in the future this property - * will be removed. This property impacts which native modules you can use in the - * renderer process. For more information on the direction Electron is going with - * renderer process restarts and usage of native modules in the renderer process - * please check out this Tracking Issue. - */ - allowRendererProcessReuse?: boolean; - /** - * A Menu property that return Menu if one has been set and null otherwise. Users - * can pass a Menu to set this property. - */ - applicationMenu?: Menu; commandLine: CommandLine; dock: Dock; /** @@ -1288,8 +1217,7 @@ declare namespace Electron { * media keys or browser commands, as well as the "Back" button built into some * mice on Windows. Commands are lowercased, underscores are replaced with hyphens, * and the APPCOMMAND_ prefix is stripped off. e.g. APPCOMMAND_BROWSER_BACKWARD is - * emitted as browser-backward. The following app commands are explictly supported - * on Linux: + * emitted as browser-backward. */ on(event: 'app-command', listener: (event: Event, command: string) => void): this; @@ -1623,10 +1551,6 @@ declare namespace Electron { * ready event of the app module is emitted. */ static removeExtension(name: string): void; - /** - * Replacement API for setBrowserView supporting work with multi browser views. - */ - addBrowserView(browserView: BrowserView): void; /** * Adds a window as a tab on this window, after the tab for the window instance. */ @@ -1637,22 +1561,11 @@ declare namespace Electron { blur(): void; blurWebView(): void; /** - * Captures a snapshot of the page within rect. Upon completion callback will be - * called with callback(image). The image is an instance of NativeImage that stores - * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon + * Same as webContents.capturePage([rect, ]callback). */ capturePage(callback: (image: NativeImage) => void): void; /** - * Captures a snapshot of the page within rect. Omitting rect will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise; - /** - * Captures a snapshot of the page within rect. Upon completion callback will be - * called with callback(image). The image is an instance of NativeImage that stores - * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon + * Same as webContents.capturePage([rect, ]callback). */ capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; /** @@ -1685,13 +1598,11 @@ declare namespace Electron { focus(): void; focusOnWebView(): void; getBounds(): Rectangle; - getBrowserView(): (BrowserView) | (null); /** - * Returns array of BrowserView what was an attached with addBrowserView or - * setBrowserView. Note: The BrowserView API is currently experimental and may - * change or be removed in future Electron releases. + * Note: The BrowserView API is currently experimental and may change or be removed + * in future Electron releases. */ - getBrowserViews(): void; + getBrowserView(): (BrowserView) | (null); getChildWindows(): BrowserWindow[]; getContentBounds(): Rectangle; getContentSize(): number[]; @@ -1715,10 +1626,13 @@ declare namespace Electron { getRepresentedFilename(): string; getSize(): number[]; /** - * Note: The title of the web page can be different from the title of the native + * Note: The title of web page can be different from the title of the native * window. */ getTitle(): string; + /** + * On Windows and Linux always returns true. + */ hasShadow(): boolean; /** * Hides the window. @@ -1770,7 +1684,7 @@ declare namespace Electron { * Same as webContents.loadFile, filePath should be a path to an HTML file relative * to the root of your application. See the webContents docs for more information. */ - loadFile(filePath: string, options?: LoadFileOptions): Promise; + loadFile(filePath: string, options?: LoadFileOptions): void; /** * Same as webContents.loadURL(url[, options]). The url can be a remote address * (e.g. http://) or a path to a local HTML file using the file:// protocol. To @@ -1778,7 +1692,7 @@ declare namespace Electron { * url.format method: You can load a URL using a POST request with URL-encoded data * by doing the following: */ - loadURL(url: string, options?: LoadURLOptions): Promise; + loadURL(url: string, options?: LoadURLOptions): void; /** * Maximizes the window. This will also show (but not focus) the window if it isn't * being displayed already. @@ -1811,11 +1725,6 @@ declare namespace Electron { * Same as webContents.reload. */ reload(): void; - removeBrowserView(browserView: BrowserView): void; - /** - * Remove the window's menu bar. - */ - removeMenu(): void; /** * Restores the window from minimized state to its previous state. */ @@ -1920,7 +1829,7 @@ declare namespace Electron { */ setFullScreenable(fullscreenable: boolean): void; /** - * Sets whether the window should have a shadow. + * Sets whether the window should have a shadow. On Windows and Linux does nothing. */ setHasShadow(hasShadow: boolean): void; /** @@ -1947,7 +1856,8 @@ declare namespace Electron { */ setMaximumSize(width: number, height: number): void; /** - * Sets the menu as the window's menu bar. + * Sets the menu as the window's menu bar, setting it to null will remove the menu + * bar. */ setMenu(menu: (Menu) | (null)): void; /** @@ -2386,12 +2296,12 @@ declare namespace Electron { // Docs: http://electronjs.org/docs/api/clipboard - availableFormats(type?: 'selection' | 'clipboard'): string[]; + availableFormats(type?: string): string[]; /** * Clears the clipboard content. */ - clear(type?: 'selection' | 'clipboard'): void; - has(format: string, type?: 'selection' | 'clipboard'): boolean; + clear(type?: string): void; + has(format: string, type?: string): boolean; read(format: string): string; /** * Returns an Object containing title and url keys representing the bookmark in the @@ -2401,24 +2311,24 @@ declare namespace Electron { readBookmark(): ReadBookmark; readBuffer(format: string): Buffer; readFindText(): string; - readHTML(type?: 'selection' | 'clipboard'): string; - readImage(type?: 'selection' | 'clipboard'): NativeImage; - readRTF(type?: 'selection' | 'clipboard'): string; - readText(type?: 'selection' | 'clipboard'): string; + readHTML(type?: string): string; + readImage(type?: string): NativeImage; + readRTF(type?: string): string; + readText(type?: string): string; /** * Writes data to the clipboard. */ - write(data: Data, type?: 'selection' | 'clipboard'): void; + write(data: Data, type?: string): void; /** * Writes the title and url into the clipboard as a bookmark. Note: Most apps on * Windows don't support pasting bookmarks into them so you can use clipboard.write * to write both a bookmark and fallback text to the clipboard. */ - writeBookmark(title: string, url: string, type?: 'selection' | 'clipboard'): void; + writeBookmark(title: string, url: string, type?: string): void; /** * Writes the buffer into the clipboard as format. */ - writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void; + writeBuffer(format: string, buffer: Buffer, type?: string): void; /** * Writes the text into the find pasteboard as plain text. This method uses * synchronous IPC when called from the renderer process. @@ -2427,61 +2337,66 @@ declare namespace Electron { /** * Writes markup to the clipboard. */ - writeHTML(markup: string, type?: 'selection' | 'clipboard'): void; + writeHTML(markup: string, type?: string): void; /** * Writes image to the clipboard. */ - writeImage(image: NativeImage, type?: 'selection' | 'clipboard'): void; + writeImage(image: NativeImage, type?: string): void; /** * Writes the text into the clipboard in RTF. */ - writeRTF(text: string, type?: 'selection' | 'clipboard'): void; + writeRTF(text: string, type?: string): void; /** * Writes the text into the clipboard as plain text. */ - writeText(text: string, type?: 'selection' | 'clipboard'): void; + writeText(text: string, type?: string): void; } interface ContentTracing extends EventEmitter { // Docs: http://electronjs.org/docs/api/content-tracing + /** + * Get the current monitoring traced data. Child processes typically cache trace + * data and only rarely flush and send trace data back to the main process. This is + * because it may be an expensive operation to send the trace data over IPC and we + * would like to avoid unneeded runtime overhead from tracing. So, to end tracing, + * we must asynchronously ask all child processes to flush any pending trace data. + * Once all child processes have acknowledged the captureMonitoringSnapshot request + * the callback will be called with a file that contains the traced data. + */ + captureMonitoringSnapshot(resultFilePath: string, callback: (resultFilePath: string) => void): void; /** * Get a set of category groups. The category groups can change as new code paths * are reached. Once all child processes have acknowledged the getCategories - * request the callback is invoked with an array of category groups. Deprecated - * Soon + * request the callback is invoked with an array of category groups. */ getCategories(callback: (categories: string[]) => void): void; - /** - * Get a set of category groups. The category groups can change as new code paths - * are reached. - */ - getCategories(): Promise; /** * Get the maximum usage across processes of trace buffer as a percentage of the * full state. When the TraceBufferUsage value is determined the callback is - * called. Deprecated Soon + * called. */ - getTraceBufferUsage(callback: (value: number) => void): void; + getTraceBufferUsage(callback: (value: number, percentage: number) => void): void; /** - * Get the maximum usage across processes of trace buffer as a percentage of the - * full state. + * Start monitoring on all processes. Monitoring begins immediately locally and + * asynchronously on child processes as soon as they receive the startMonitoring + * request. Once all child processes have acknowledged the startMonitoring request + * the callback will be called. */ - getTraceBufferUsage(): Promise; + startMonitoring(options: StartMonitoringOptions, callback: Function): void; /** * Start recording on all processes. Recording begins immediately locally and * asynchronously on child processes as soon as they receive the EnableRecording * request. The callback will be called once all child processes have acknowledged - * the startRecording request. Deprecated Soon + * the startRecording request. */ startRecording(options: (TraceCategoriesAndOptions) | (TraceConfig), callback: Function): void; /** - * Start recording on all processes. Recording begins immediately locally and - * asynchronously on child processes as soon as they receive the EnableRecording - * request. + * Stop monitoring on all processes. Once all child processes have acknowledged the + * stopMonitoring request the callback is called. */ - startRecording(options: (TraceCategoriesAndOptions) | (TraceConfig)): Promise; + stopMonitoring(callback: Function): void; /** * Stop recording on all processes. Child processes typically cache trace data and * only rarely flush and send trace data back to the main process. This helps to @@ -2491,18 +2406,9 @@ declare namespace Electron { * acknowledged the stopRecording request, callback will be called with a file that * contains the traced data. Trace data will be written into resultFilePath if it * is not empty or into a temporary file. The actual file path will be passed to - * callback if it's not null. Deprecated Soon + * callback if it's not null. */ stopRecording(resultFilePath: string, callback: (resultFilePath: string) => void): void; - /** - * Stop recording on all processes. Child processes typically cache trace data and - * only rarely flush and send trace data back to the main process. This helps to - * minimize the runtime overhead of tracing since sending trace data over IPC can - * be an expensive operation. So, to end tracing, we must asynchronously ask all - * child processes to flush any pending trace data. Trace data will be written into - * resultFilePath if it is not empty or into a temporary file. - */ - stopRecording(resultFilePath: string): Promise; } interface Cookie { @@ -2614,37 +2520,20 @@ declare namespace Electron { /** * Writes any unwritten cookies data to disk. */ - flushStore(): Promise; - /** - * Writes any unwritten cookies data to disk. Deprecated Soon - */ flushStore(callback: Function): void; - /** - * Sends a request to get all cookies matching filter, and resolves a promise with - * the response. - */ - get(filter: Filter): Promise; /** * Sends a request to get all cookies matching filter, callback will be called with - * callback(error, cookies) on complete. Deprecated Soon + * callback(error, cookies) on complete. */ get(filter: Filter, callback: (error: Error, cookies: Cookie[]) => void): void; - /** - * Removes the cookies matching url and name - */ - remove(url: string, name: string): Promise; /** * Removes the cookies matching url and name, callback will called with callback() - * on complete. Deprecated Soon + * on complete. */ remove(url: string, name: string, callback: Function): void; - /** - * Sets a cookie with details. - */ - set(details: Details): Promise; /** * Sets a cookie with details, callback will be called with callback(error) on - * complete. Deprecated Soon + * complete. */ set(details: Details, callback: (error: Error) => void): void; } @@ -2672,15 +2561,15 @@ declare namespace Electron { id: string; } - interface CrashReporter { + interface CrashReporter extends EventEmitter { // Docs: http://electronjs.org/docs/api/crash-reporter /** * Set an extra parameter to be sent with the crash report. The values specified * here will be sent in addition to any values set via the extra option when start - * was called. This API is only available on macOS and windows, if you need to - * add/update extra parameters on Linux after your first call to start you can call + * was called. This API is only available on macOS, if you need to add/update extra + * parameters on Linux and Windows after your first call to start you can call * start again with the updated extra options. */ addExtraParameter(key: string, value: string): void; @@ -2724,10 +2613,13 @@ declare namespace Electron { * reports from them, use process.crashReporter.start instead. Pass the same * options as above along with an additional one called crashesDirectory that * should point to a directory to store the crash reports temporarily. You can test - * this out by calling process.crash() to crash the child process. Note: If you - * need send additional/updated extra parameters after your first call start you - * can call addExtraParameter on macOS or call start again with the new/updated - * extra parameters on Linux and Windows. Note: On macOS and windows, Electron uses + * this out by calling process.crash() to crash the child process. Note: To collect + * crash reports from child process in Windows, you need to add this extra code as + * well. This will start the process that will monitor and send the crash reports. + * Replace submitURL, productName and crashesDirectory with appropriate values. + * Note: If you need send additional/updated extra parameters after your first call + * start you can call addExtraParameter on macOS or call start again with the + * new/updated extra parameters on Linux and Windows. Note: On macOS, Electron uses * a new crashpad client for crash collection and reporting. If you want to enable * crash reporting, initializing crashpad from the main process using * crashReporter.start is required regardless of which process you want to collect @@ -2739,17 +2631,6 @@ declare namespace Electron { start(options: CrashReporterStartOptions): void; } - interface CustomScheme { - - // Docs: http://electronjs.org/docs/api/structures/custom-scheme - - privileges?: Privileges; - /** - * Custom schemes to be registered with options. - */ - scheme: string; - } - class Debugger extends EventEmitter { // Docs: http://electronjs.org/docs/api/debugger @@ -2830,14 +2711,10 @@ declare namespace Electron { */ detach(): void; isAttached(): boolean; - /** - * Send given command to the debugging target. Deprecated Soon - */ - sendCommand(method: string, commandParams?: any, callback?: (error: any, result: any) => void): void; /** * Send given command to the debugging target. */ - sendCommand(method: string, commandParams?: any): Promise; + sendCommand(method: string, commandParams?: any, callback?: (error: any, result: any) => void): void; } interface DesktopCapturer extends EventEmitter { @@ -2848,22 +2725,15 @@ declare namespace Electron { * Starts gathering information about all available desktop media sources, and * calls callback(error, sources) when finished. sources is an array of * DesktopCapturerSource objects, each DesktopCapturerSource represents a screen or - * an individual window that can be captured. Deprecated Soon + * an individual window that can be captured. */ getSources(options: SourcesOptions, callback: (error: Error, sources: DesktopCapturerSource[]) => void): void; - getSources(options: SourcesOptions): Promise; } interface DesktopCapturerSource { // Docs: http://electronjs.org/docs/api/structures/desktop-capturer-source - /** - * An icon image of the application that owns the window or null if the source has - * a type screen. The size of the icon is not known in advance and depends on what - * the the application provides. - */ - appIcon: NativeImage; /** * A unique identifier that will correspond to the id of the matching returned by * the . On some platforms, this is equivalent to the XX portion of the id field @@ -2900,7 +2770,7 @@ declare namespace Electron { * information, and gives the user the option of trusting/importing the * certificate. If you provide a browserWindow argument the dialog will be attached * to the parent window, making it modal. On Windows the options are more limited, - * due to the Win32 APIs used: Deprecated Soon + * due to the Win32 APIs used: */ showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions, callback: Function): void; /** @@ -2910,14 +2780,6 @@ declare namespace Electron { * to the parent window, making it modal. On Windows the options are more limited, * due to the Win32 APIs used: */ - showCertificateTrustDialog(options: CertificateTrustDialogOptions): Promise; - /** - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a browserWindow argument the dialog will be attached - * to the parent window, making it modal. On Windows the options are more limited, - * due to the Win32 APIs used: Deprecated Soon - */ showCertificateTrustDialog(options: CertificateTrustDialogOptions, callback: Function): void; /** * On macOS, this displays a modal dialog that shows a message and certificate @@ -2926,14 +2788,6 @@ declare namespace Electron { * to the parent window, making it modal. On Windows the options are more limited, * due to the Win32 APIs used: */ - showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions): Promise; - /** - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a browserWindow argument the dialog will be attached - * to the parent window, making it modal. On Windows the options are more limited, - * due to the Win32 APIs used: Deprecated Soon - */ showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions, callback: Function): void; /** * Displays a modal dialog that shows an error message. This API can be called @@ -2944,140 +2798,73 @@ declare namespace Electron { showErrorBox(title: string, content: string): void; /** * Shows a message box, it will block the process until the message box is closed. - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. + * It returns the index of the clicked button. The browserWindow argument allows + * the dialog to attach itself to a parent window, making it modal. If a callback + * is passed, the dialog will not block the process. The API call will be + * asynchronous and the result will be passed via callback(response). */ - showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions): Promise; - /** - * Shows a message box, it will block the process until the message box is closed. - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. - */ - showMessageBox(options: MessageBoxOptions): Promise; + showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions, callback?: (response: number, checkboxChecked: boolean) => void): number; /** * Shows a message box, it will block the process until the message box is closed. * It returns the index of the clicked button. The browserWindow argument allows - * the dialog to attach itself to a parent window, making it modal. + * the dialog to attach itself to a parent window, making it modal. If a callback + * is passed, the dialog will not block the process. The API call will be + * asynchronous and the result will be passed via callback(response). */ - showMessageBoxSync(browserWindow: BrowserWindow, options: MessageBoxSyncOptions): number; - /** - * Shows a message box, it will block the process until the message box is closed. - * It returns the index of the clicked button. The browserWindow argument allows - * the dialog to attach itself to a parent window, making it modal. - */ - showMessageBoxSync(options: MessageBoxSyncOptions): number; + showMessageBox(options: MessageBoxOptions, callback?: (response: number, checkboxChecked: boolean) => void): number; /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can * be displayed or selected when you want to limit the user to a specific type. For * example: The extensions array should contain extensions without wildcards or * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use - * the '*' wildcard (no other wildcard is supported). Note: On Windows and Linux an - * open dialog can not be both a file selector and a directory selector, so if you - * set properties to ['openFile', 'openDirectory'] on these platforms, a directory - * selector will be shown. + * the '*' wildcard (no other wildcard is supported). If a callback is passed, the + * API call will be asynchronous and the result will be passed via + * callback(filenames). Note: On Windows and Linux an open dialog can not be both a + * file selector and a directory selector, so if you set properties to ['openFile', + * 'openDirectory'] on these platforms, a directory selector will be shown. */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: Function): Promise; + showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can * be displayed or selected when you want to limit the user to a specific type. For * example: The extensions array should contain extensions without wildcards or * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use - * the '*' wildcard (no other wildcard is supported). Note: On Windows and Linux an - * open dialog can not be both a file selector and a directory selector, so if you - * set properties to ['openFile', 'openDirectory'] on these platforms, a directory - * selector will be shown. + * the '*' wildcard (no other wildcard is supported). If a callback is passed, the + * API call will be asynchronous and the result will be passed via + * callback(filenames). Note: On Windows and Linux an open dialog can not be both a + * file selector and a directory selector, so if you set properties to ['openFile', + * 'openDirectory'] on these platforms, a directory selector will be shown. */ - showOpenDialog(options: OpenDialogOptions, callback?: Function): Promise; + showOpenDialog(options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can - * be displayed or selected when you want to limit the user to a specific type. For - * example: The extensions array should contain extensions without wildcards or - * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use - * the '*' wildcard (no other wildcard is supported). Note: On Windows and Linux an - * open dialog can not be both a file selector and a directory selector, so if you - * set properties to ['openFile', 'openDirectory'] on these platforms, a directory - * selector will be shown. + * be displayed, see dialog.showOpenDialog for an example. If a callback is passed, + * the API call will be asynchronous and the result will be passed via + * callback(filename). */ - showOpenDialogSync(browserWindow: BrowserWindow, options: OpenDialogSyncOptions): (string[]) | (undefined); + showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can - * be displayed or selected when you want to limit the user to a specific type. For - * example: The extensions array should contain extensions without wildcards or - * dots (e.g. 'png' is good but '.png' and '*.png' are bad). To show all files, use - * the '*' wildcard (no other wildcard is supported). Note: On Windows and Linux an - * open dialog can not be both a file selector and a directory selector, so if you - * set properties to ['openFile', 'openDirectory'] on these platforms, a directory - * selector will be shown. + * be displayed, see dialog.showOpenDialog for an example. If a callback is passed, + * the API call will be asynchronous and the result will be passed via + * callback(filename). */ - showOpenDialogSync(options: OpenDialogSyncOptions): (string[]) | (undefined); - /** - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. The filters specifies an array of file types that can - * be displayed, see dialog.showOpenDialog for an example. Note: On macOS, using - * the asynchronous version is recommended to avoid issues when expanding and - * collapsing the dialog. - */ - showSaveDialog(options: SaveDialogOptions): Promise; - /** - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. The filters specifies an array of file types that can - * be displayed, see dialog.showOpenDialog for an example. Note: On macOS, using - * the asynchronous version is recommended to avoid issues when expanding and - * collapsing the dialog. - */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions): Promise; - /** - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. The filters specifies an array of file types that can - * be displayed, see dialog.showOpenDialog for an example. - */ - showSaveDialogSync(options: SaveDialogSyncOptions): (string) | (undefined); - /** - * The browserWindow argument allows the dialog to attach itself to a parent - * window, making it modal. The filters specifies an array of file types that can - * be displayed, see dialog.showOpenDialog for an example. - */ - showSaveDialogSync(browserWindow: BrowserWindow, options: SaveDialogSyncOptions): (string) | (undefined); + showSaveDialog(options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); } interface Display { // Docs: http://electronjs.org/docs/api/structures/display - /** - * Can be available, unavailable, unknown. - */ - accelerometerSupport: ('available' | 'unavailable' | 'unknown'); bounds: Rectangle; - /** - * The number of bits per pixel. - */ - colorDepth: number; - /** - * represent a color space (three-dimensional object which contains all realizable - * color combinations) for the purpose of color conversions - */ - colorSpace: string; - /** - * The number of bits per color component. - */ - depthPerComponent: number; /** * Unique identifier associated with the display. */ id: number; - /** - * true for an internal display and false for an external display - */ - internal: boolean; - /** - * Whether or not the display is a monochrome display. - */ - monochrome: boolean; /** * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. */ @@ -3164,7 +2951,6 @@ declare namespace Electron { getLastModifiedTime(): string; getMimeType(): string; getReceivedBytes(): number; - getSaveDialogOptions(): SaveDialogOptions; getSavePath(): string; getStartTime(): number; /** @@ -3191,12 +2977,6 @@ declare namespace Electron { * received bytes and restart the download from the beginning. */ resume(): void; - /** - * This API allows the user to set custom options for the save dialog that opens - * for the download item by default. The API is only available in session's - * will-download callback function. - */ - setSaveDialogOptions(options: SaveDialogOptions): void; /** * The API is only available in session's will-download callback function. If user * doesn't set the save path via the API, Electron will use the original routine to @@ -3205,13 +2985,6 @@ declare namespace Electron { setSavePath(path: string): void; } - interface Event extends GlobalEvent { - - // Docs: http://electronjs.org/docs/api/structures/event - - preventDefault: (() => void); - } - interface FileFilter { // Docs: http://electronjs.org/docs/api/structures/file-filter @@ -3239,17 +3012,7 @@ declare namespace Electron { * on macOS 10.14 Mojave unless the app has been authorized as a trusted * accessibility client: */ - register(accelerator: Accelerator, callback: Function): boolean; - /** - * Registers a global shortcut of all accelerator items in accelerators. The - * callback is called when any of the registered shortcuts are pressed by the user. - * When a given accelerator is already taken by other applications, this call will - * silently fail. This behavior is intended by operating systems, since they don't - * want applications to fight for global shortcuts. The following accelerators will - * not be registered successfully on macOS 10.14 Mojave unless the app has been - * authorized as a trusted accessibility client: - */ - registerAll(accelerators: string[], callback: Function): void; + register(accelerator: Accelerator, callback: Function): void; /** * Unregisters the global shortcut of accelerator. */ @@ -3354,25 +3117,16 @@ declare namespace Electron { * Completes the pending transactions corresponding to the date. */ finishTransactionByDate(date: string): void; - /** - * Retrieves the product descriptions. Deprecated Soon - */ - getProducts(productIDs: string[], callback: (products: Product[]) => void): void; /** * Retrieves the product descriptions. */ - getProducts(productIDs: string[]): Promise; + getProducts(productIDs: string[], callback: (products: Product[]) => void): void; getReceiptURL(): string; - /** - * You should listen for the transactions-updated event as soon as possible and - * certainly before you call purchaseProduct. Deprecated Soon - */ - purchaseProduct(productID: string, quantity?: number, callback?: (isProductValid: boolean) => void): void; /** * You should listen for the transactions-updated event as soon as possible and * certainly before you call purchaseProduct. */ - purchaseProduct(productID: string, quantity?: number): Promise; + purchaseProduct(productID: string, quantity?: number, callback?: (isProductValid: boolean) => void): void; } class IncomingMessage extends EventEmitter { @@ -3474,12 +3228,12 @@ declare namespace Electron { * Listens to channel, when a new message arrives listener would be called with * listener(event, args...). */ - on(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; + on(channel: string, listener: Function): this; /** * Adds a one time listener function for the event. This listener is invoked only * the next time a message is sent to channel, after which it is removed. */ - once(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; + once(channel: string, listener: Function): this; /** * Removes listeners of the specified channel. */ @@ -3491,31 +3245,6 @@ declare namespace Electron { removeListener(channel: string, listener: Function): this; } - interface IpcMainEvent extends Event { - - // Docs: http://electronjs.org/docs/api/structures/ipc-main-event - - /** - * The ID of the renderer frame that sent this message - */ - frameId: number; - /** - * A function that will send an IPC message to the renderer frame that sent the - * original message that you are currently handling. You should use this method to - * "reply" to the sent message in order to guaruntee the reply will go to the - * correct process and frame. - */ - reply: Function; - /** - * Set this to the value to be returned in a syncronous message - */ - returnValue: any; - /** - * Returns the webContents that sent the message - */ - sender: WebContents; - } - interface IpcRenderer extends EventEmitter { // Docs: http://electronjs.org/docs/api/ipc-renderer @@ -3524,12 +3253,12 @@ declare namespace Electron { * Listens to channel, when a new message arrives listener would be called with * listener(event, args...). */ - on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; + on(channel: string, listener: Function): this; /** * Adds a one time listener function for the event. This listener is invoked only * the next time a message is sent to channel, after which it is removed. */ - once(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; + once(channel: string, listener: Function): this; /** * Removes all listeners, or those of the specified channel. */ @@ -3566,23 +3295,6 @@ declare namespace Electron { sendToHost(channel: string, ...args: any[]): void; } - interface IpcRendererEvent extends Event { - - // Docs: http://electronjs.org/docs/api/structures/ipc-renderer-event - - /** - * The IpcRenderer instance that emitted the event originally - */ - sender: IpcRenderer; - /** - * The webContents.id that sent the message, you can call - * event.sender.sendTo(event.senderId, ...) to reply to the message, see for more - * information. This only applies to messages sent from a different renderer. - * Messages sent directly from the main process set event.senderId to 0. - */ - senderId: number; - } - interface JumpListCategory { // Docs: http://electronjs.org/docs/api/structures/jump-list-category @@ -3646,37 +3358,6 @@ declare namespace Electron { * One of the following: */ type?: ('task' | 'separator' | 'file'); - /** - * The working directory. Default is empty. - */ - workingDirectory?: string; - } - - interface KeyboardEvent extends Event { - - // Docs: http://electronjs.org/docs/api/structures/keyboard-event - - /** - * whether an Alt key was used in an accelerator to trigger the Event - */ - altKey?: boolean; - /** - * whether the Control key was used in an accelerator to trigger the Event - */ - ctrlKey?: boolean; - /** - * whether a meta key was used in an accelerator to trigger the Event - */ - metaKey?: boolean; - /** - * whether a Shift key was used in an accelerator to trigger the Event - */ - shiftKey?: boolean; - /** - * whether an accelerator was used to trigger the event as opposed to another user - * gesture like mouse click - */ - triggeredByAccelerator?: boolean; } interface MemoryUsageDetails { @@ -3712,7 +3393,7 @@ declare namespace Electron { * usage can be referenced above. You can also attach other fields to the element * of the template and they will become properties of the constructed menu items. */ - static buildFromTemplate(template: Array<(MenuItemConstructorOptions) | (MenuItem)>): Menu; + static buildFromTemplate(template: MenuItemConstructorOptions[]): Menu; /** * Note: The returned Menu instance doesn't support dynamic addition or removal of * menu items. Instance properties can still be dynamically modified. @@ -3727,16 +3408,9 @@ declare namespace Electron { static sendActionToFirstResponder(action: string): void; /** * Sets menu as the application menu on macOS. On Windows and Linux, the menu will - * be set as each window's top menu. Also on Windows and Linux, you can use a & in - * the top-level item name to indicate which letter should get a generated - * accelerator. For example, using &File for the file menu would result in a - * generated Alt-F accelerator that opens the associated menu. The indicated - * character in the button label gets an underline. The & character is not - * displayed on the button label. Passing null will suppress the default menu. On - * Windows and Linux, this has the additional effect of removing the menu bar from - * the window. Note: The default menu will be created automatically if the app does - * not set one. It contains standard items such as File, Edit, View, Window and - * Help. + * be set as each window's top menu. Passing null will remove the menu bar on + * Windows and Linux but has no effect on macOS. Note: This API has to be called + * after the ready event of app module. */ static setApplicationMenu(menu: (Menu) | (null)): void; /** @@ -3764,20 +3438,10 @@ declare namespace Electron { // Docs: http://electronjs.org/docs/api/menu-item constructor(options: MenuItemConstructorOptions); - accelerator: string; checked: boolean; click: Function; - commandId: number; enabled: boolean; - icon: NativeImage; - id: string; label: string; - menu: Menu; - registerAccelerator: boolean; - role: string; - sublabel: string; - submenu: Menu; - type: string; visible: boolean; } @@ -3804,13 +3468,7 @@ declare namespace Electron { */ static createEmpty(): NativeImage; /** - * Creates a new NativeImage instance from buffer that contains the raw bitmap - * pixel data returned by toBitmap(). The specific format is platform-dependent. - */ - static createFromBitmap(buffer: Buffer, options: CreateFromBitmapOptions): NativeImage; - /** - * Creates a new NativeImage instance from buffer. Tries to decode as PNG or JPEG - * first. + * Creates a new NativeImage instance from buffer. */ static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage; /** @@ -3896,16 +3554,11 @@ declare namespace Electron { * Starts recording network events to path. */ startLogging(path: string): void; - /** - * Stops recording network events. If not called, net logging will automatically - * end when app quits. Deprecated Soon - */ - stopLogging(callback?: (path: string) => void): void; /** * Stops recording network events. If not called, net logging will automatically * end when app quits. */ - stopLogging(): Promise; + stopLogging(callback?: (path: string) => void): void; /** * A Boolean property that indicates whether network logs are recorded. */ @@ -4084,15 +3737,6 @@ declare namespace Electron { once(event: 'unlock-screen', listener: Function): this; addListener(event: 'unlock-screen', listener: Function): this; removeListener(event: 'unlock-screen', listener: Function): this; - /** - * Calculate the system idle state. idleThreshold is the amount of time (in - * seconds) before considered idle. locked is available on supported systems only. - */ - getSystemIdleState(idleThreshold: number): ('active' | 'idle' | 'locked' | 'unknown'); - /** - * Calculate system idle time in seconds. - */ - getSystemIdleTime(): number; /** * Calculate the system idle state. idleThreshold is the amount of time (in * seconds) before considered idle. callback will be called synchronously on some @@ -4138,26 +3782,6 @@ declare namespace Electron { status: number; } - interface ProcessMemoryInfo { - - // Docs: http://electronjs.org/docs/api/structures/process-memory-info - - /** - * The amount of memory not shared by other processes, such as JS heap or HTML - * content in Kilobytes. - */ - private: number; - /** - * and The amount of memory currently pinned to actual physical RAM in Kilobytes. - */ - residentSet: number; - /** - * The amount of memory shared between processes, typically memory consumed by the - * Electron code itself in Kilobytes. - */ - shared: number; - } - interface ProcessMetric { // Docs: http://electronjs.org/docs/api/structures/process-metric @@ -4171,9 +3795,9 @@ declare namespace Electron { */ pid: number; /** - * Process type. One of the following values: + * Process type (Browser or Tab or GPU etc). */ - type: ('Browser' | 'Tab' | 'Utility' | 'Zygote' | 'GPU' | 'Unknown'); + type: string; } interface Product { @@ -4188,16 +3812,15 @@ declare namespace Electron { * A string that identifies the version of the content. */ contentVersion: string; + /** + * A Boolean value that indicates whether the App Store has downloadable content + * for this product. + */ + downloadable: boolean; /** * The locale formatted price of the product. */ formattedPrice: string; - /** - * A Boolean value that indicates whether the App Store has downloadable content - * for this product. true if at least one file has been associated with the - * product. - */ - isDownloadable: boolean; /** * A description of the product. */ @@ -4247,10 +3870,9 @@ declare namespace Electron { interceptStringProtocol(scheme: string, handler: (request: InterceptStringProtocolRequest, callback: (data?: string) => void) => void, completion?: (error: Error) => void): void; /** * The callback will be called with a boolean that indicates whether there is - * already a handler for scheme. Deprecated Soon + * already a handler for scheme. */ - isProtocolHandled(scheme: string, callback: (handled: boolean) => void): void; - isProtocolHandled(scheme: string): Promise; + isProtocolHandled(scheme: string, callback: (error: Error) => void): void; /** * Registers a protocol of scheme that will send a Buffer as a response. The usage * is the same with registerFileProtocol, except that the callback should be called @@ -4265,14 +3887,13 @@ declare namespace Electron { * scheme is successfully registered or completion(error) when failed. To handle * the request, the callback should be called with either the file's path or an * object that has a path property, e.g. callback(filePath) or callback({ path: - * filePath }). The object may also have a headers property which gives a map of - * headers to values for the response headers, e.g. callback({ path: filePath, - * headers: {"Content-Security-Policy": "default-src 'none'"]}). When callback is - * called with nothing, a number, or an object that has an error property, the - * request will fail with the error number you specified. For the available error - * numbers you can use, please see the net error list. By default the scheme is - * treated like http:, which is parsed differently than protocols that follow the - * "generic URI syntax" like file:. + * filePath }). When callback is called with nothing, a number, or an object that + * has an error property, the request will fail with the error number you + * specified. For the available error numbers you can use, please see the net error + * list. By default the scheme is treated like http:, which is parsed differently + * than protocols that follow the "generic URI syntax" like file:, so you probably + * want to call protocol.registerStandardSchemes to have your scheme treated as a + * standard scheme. */ registerFileProtocol(scheme: string, handler: (request: RegisterFileProtocolRequest, callback: (filePath?: string) => void) => void, completion?: (error: Error) => void): void; /** @@ -4284,31 +3905,24 @@ declare namespace Electron { * set session to null. For POST requests the uploadData object must be provided. */ registerHttpProtocol(scheme: string, handler: (request: RegisterHttpProtocolRequest, callback: (redirectRequest: RedirectRequest) => void) => void, completion?: (error: Error) => void): void; + registerServiceWorkerSchemes(schemes: string[]): void; /** - * Note: This method can only be used before the ready event of the app module gets - * emitted and can be called only once. Registers the scheme as standard, secure, - * bypasses content security policy for resources, allows registering ServiceWorker - * and supports fetch API. Specify a privilege with the value of true to enable the - * capability. An example of registering a privileged scheme, with bypassing - * Content Security Policy: A standard scheme adheres to what RFC 3986 calls - * generic URI syntax. For example http and https are standard schemes, while file - * is not. Registering a scheme as standard, will allow relative and absolute - * resources to be resolved correctly when served. Otherwise the scheme will behave - * like the file protocol, but without the ability to resolve relative URLs. For - * example when you load following page with custom protocol without registering it - * as standard scheme, the image will not be loaded because non-standard schemes - * can not recognize relative URLs: Registering a scheme as standard will allow - * access to files through the FileSystem API. Otherwise the renderer will throw a - * security error for the scheme. By default web storage apis (localStorage, - * sessionStorage, webSQL, indexedDB, cookies) are disabled for non standard - * schemes. So in general if you want to register a custom protocol to replace the - * http protocol, you have to register it as a standard scheme. - * protocol.registerSchemesAsPrivileged can be used to replicate the functionality - * of the previous protocol.registerStandardSchemes, webFrame.registerURLSchemeAs* - * and protocol.registerServiceWorkerSchemes functions that existed prior to - * Electron 5.0.0, for example: before (<= v4.x) after (>= v5.x) + * A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example + * http and https are standard schemes, while file is not. Registering a scheme as + * standard, will allow relative and absolute resources to be resolved correctly + * when served. Otherwise the scheme will behave like the file protocol, but + * without the ability to resolve relative URLs. For example when you load + * following page with custom protocol without registering it as standard scheme, + * the image will not be loaded because non-standard schemes can not recognize + * relative URLs: Registering a scheme as standard will allow access to files + * through the FileSystem API. Otherwise the renderer will throw a security error + * for the scheme. By default web storage apis (localStorage, sessionStorage, + * webSQL, indexedDB, cookies) are disabled for non standard schemes. So in general + * if you want to register a custom protocol to replace the http protocol, you have + * to register it as a standard scheme: Note: This method can only be used before + * the ready event of the app module gets emitted. */ - registerSchemesAsPrivileged(customSchemes: CustomScheme[]): void; + registerStandardSchemes(schemes: string[], options?: RegisterStandardSchemesOptions): void; /** * Registers a protocol of scheme that will send a Readable as a response. The * usage is similar to the other register{Any}Protocol, except that the callback @@ -4589,33 +4203,22 @@ declare namespace Electron { * authentication. */ allowNTLMCredentialsForDomains(domains: string): void; - clearAuthCache(): Promise; - clearAuthCache(options: (RemovePassword) | (RemoveClientCertificate)): Promise; /** - * Clears the session’s HTTP authentication cache. Deprecated Soon + * Clears the session’s HTTP authentication cache. */ - clearAuthCache(options: (RemovePassword) | (RemoveClientCertificate), callback: Function): void; + clearAuthCache(options: (RemovePassword) | (RemoveClientCertificate), callback?: Function): void; /** * Clears the session’s HTTP cache. */ - clearCache(): Promise; - /** - * Clears the session’s HTTP cache. Deprecated Soon - */ - clearCache(callback: (error: number) => void): void; + clearCache(callback: Function): void; /** * Clears the host resolver cache. */ - clearHostResolverCache(): Promise; - /** - * Clears the host resolver cache. Deprecated Soon - */ clearHostResolverCache(callback?: Function): void; /** - * Clears the storage data for the current session. Deprecated Soon + * Clears the data of web storages. */ clearStorageData(options?: ClearStorageDataOptions, callback?: Function): void; - clearStorageData(options?: ClearStorageDataOptions): Promise; /** * Allows resuming cancelled or interrupted downloads from previous Session. The * API will generate a DownloadItem that can be accessed with the will-download @@ -4637,22 +4240,16 @@ declare namespace Electron { * Writes any unwritten DOMStorage data to disk. */ flushStorageData(): void; - /** - * Deprecated Soon - */ getBlobData(identifier: string, callback: (result: Buffer) => void): void; - getBlobData(identifier: string): Promise; - getCacheSize(): Promise; /** - * Callback is invoked with the session's current cache size. Deprecated Soon + * Callback is invoked with the session's current cache size. */ - getCacheSize(callback: (size: number, error: number) => void): void; + getCacheSize(callback: (size: number) => void): void; getPreloads(): string[]; getUserAgent(): string; - resolveProxy(url: string): Promise; /** * Resolves the proxy information for url. The callback will be called with - * callback(proxy) when the request is performed. Deprecated Soon + * callback(proxy) when the request is performed. */ resolveProxy(url: string, callback: (proxy: string) => void): void; /** @@ -4691,13 +4288,6 @@ declare namespace Electron { * proxyRules has to follow the rules below: For example: The proxyBypassRules is a * comma separated list of rules described below: */ - setProxy(config: Config): Promise; - /** - * Sets the proxy settings. When pacScript and proxyRules are provided together, - * the proxyRules option is ignored and pacScript configuration is applied. The - * proxyRules has to follow the rules below: For example: The proxyBypassRules is a - * comma separated list of rules described below: Deprecated Soon - */ setProxy(config: Config, callback: Function): void; /** * Overrides the userAgent and acceptLanguages for this session. The @@ -4729,12 +4319,7 @@ declare namespace Electron { * Open the given external protocol URL in the desktop's default manner. (For * example, mailto: URLs in the user's default mail agent). */ - openExternal(url: string, options?: OpenExternalOptions): Promise; - /** - * Open the given external protocol URL in the desktop's default manner. (For - * example, mailto: URLs in the user's default mail agent). Deprecated - */ - openExternalSync(url: string, options?: OpenExternalSyncOptions): boolean; + openExternal(url: string, options?: OpenExternalOptions, callback?: (error: Error) => void): boolean; /** * Open the given file in the desktop's default manner. */ @@ -4747,7 +4332,7 @@ declare namespace Electron { /** * Show the given file in a file manager. If possible, select the file. */ - showItemInFolder(fullPath: string): void; + showItemInFolder(fullPath: string): boolean; /** * Creates or updates a shortcut link at shortcutPath. */ @@ -4848,48 +4433,28 @@ declare namespace Electron { once(event: 'color-changed', listener: (event: Event) => void): this; addListener(event: 'color-changed', listener: (event: Event) => void): this; removeListener(event: 'color-changed', listener: (event: Event) => void): this; - on(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - once(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - addListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; - removeListener(event: 'high-contrast-color-scheme-changed', listener: (event: Event, - /** - * `true` if a high contrast theme is being used, `false` otherwise. - */ - highContrastColorScheme: boolean) => void): this; on(event: 'inverted-color-scheme-changed', listener: (event: Event, /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; once(event: 'inverted-color-scheme-changed', listener: (event: Event, /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; addListener(event: 'inverted-color-scheme-changed', listener: (event: Event, /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; removeListener(event: 'inverted-color-scheme-changed', listener: (event: Event, /** - * `true` if an inverted color scheme (a high contrast color scheme with light text - * and dark backgrounds) is being used, `false` otherwise. + * `true` if an inverted color scheme, such as a high contrast theme, is being + * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; /** @@ -4902,26 +4467,15 @@ declare namespace Electron { * was not required until macOS 10.14 Mojave, so this method will always return * true if your system is running 10.13 High Sierra or lower. */ - askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise; - /** - * NOTE: This API will return false on macOS systems older than Sierra 10.12.2. - */ - canPromptTouchID(): boolean; - /** - * This API is only available on macOS 10.14 Mojave or newer. - */ + askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise; getAccentColor(): string; - /** - * Returns an object with system animation settings. - */ - getAnimationSettings(): AnimationSettings; /** * Gets the macOS appearance setting that you have declared you want for your * application, maps to NSApplication.appearance. You can use the * setAppLevelAppearance API to set this value. */ getAppLevelAppearance(): ('dark' | 'light' | 'unknown'); - getColor(color: '3d-dark-shadow' | '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text' | 'alternate-selected-control-text' | 'alternate-selected-control-text' | 'control-background' | 'control' | 'control-text' | 'disabled-control-text' | 'find-highlight' | 'grid' | 'header-text' | 'highlight' | 'keyboard-focus-indicator' | 'label' | 'link' | 'placeholder-text' | 'quaternary-label' | 'scrubber-textured-background' | 'secondary-label' | 'selected-content-background' | 'selected-control' | 'selected-control-text' | 'selected-menu-item' | 'selected-text-background' | 'selected-text' | 'separator' | 'shadow' | 'tertiary-label' | 'text-background' | 'text' | 'under-page-background' | 'unemphasized-selected-content-background' | 'unemphasized-selected-text-background' | 'unemphasized-selected-text' | 'window-background' | 'window-frame-text'): string; + getColor(color: '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text'): string; /** * Gets the macOS appearance setting that is currently applied to your application, * maps to NSApplication.effectiveAppearance Please note that until Electron is @@ -4938,12 +4492,6 @@ declare namespace Electron { * always return granted if your system is running 10.13 High Sierra or lower. */ getMediaAccessStatus(mediaType: string): ('not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown'); - /** - * Returns one of several standard system colors that automatically adapt to - * vibrancy and changes in accessibility settings like 'Increase contrast' and - * 'Reduce transparency'. See Apple Documentation for more details. - */ - getSystemColor(color: 'blue' | 'brown' | 'gray' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'yellow'): void; /** * Some popular key and types are: */ @@ -4954,7 +4502,6 @@ declare namespace Electron { */ isAeroGlassEnabled(): boolean; isDarkMode(): boolean; - isHighContrastColorScheme(): boolean; isInvertedColorScheme(): boolean; isSwipeTrackingFromScrollEventsEnabled(): boolean; isTrustedAccessibilityClient(prompt: boolean): boolean; @@ -4967,22 +4514,12 @@ declare namespace Electron { * Posts event as native notifications of macOS. The userInfo is an Object that * contains the user information dictionary sent along with the notification. */ - postNotification(event: string, userInfo: any, deliverImmediately?: boolean): void; + postNotification(event: string, userInfo: any): void; /** * Posts event as native notifications of macOS. The userInfo is an Object that * contains the user information dictionary sent along with the notification. */ postWorkspaceNotification(event: string, userInfo: any): void; - /** - * This API itself will not protect your user data; rather, it is a mechanism to - * allow you to do so. Native apps will need to set Access Control Constants like - * kSecAccessControlUserPresence on the their keychain entry so that reading it - * would auto-prompt for Touch ID biometric consent. This could be done with - * node-keytar, such that one would store an encryption key with node-keytar and - * only fetch it if promptTouchID() resolves. NOTE: This API will return a rejected - * Promise on macOS systems older than Sierra 10.12.2. - */ - promptTouchID(reason: string): Promise; /** * Add the specified defaults to your application's NSUserDefaults. */ @@ -5071,10 +4608,6 @@ declare namespace Electron { * The string to be displayed in a JumpList. */ title: string; - /** - * The working directory. Default is empty. - */ - workingDirectory?: string; } interface ThumbarButton { @@ -5296,7 +4829,7 @@ declare namespace Electron { /** * Emitted when the tray icon is clicked. */ - on(event: 'click', listener: (event: KeyboardEvent, + on(event: 'click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5305,7 +4838,7 @@ declare namespace Electron { * The position of the event. */ position: Point) => void): this; - once(event: 'click', listener: (event: KeyboardEvent, + once(event: 'click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5314,7 +4847,7 @@ declare namespace Electron { * The position of the event. */ position: Point) => void): this; - addListener(event: 'click', listener: (event: KeyboardEvent, + addListener(event: 'click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5323,7 +4856,7 @@ declare namespace Electron { * The position of the event. */ position: Point) => void): this; - removeListener(event: 'click', listener: (event: KeyboardEvent, + removeListener(event: 'click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5335,22 +4868,22 @@ declare namespace Electron { /** * Emitted when the tray icon is double clicked. */ - on(event: 'double-click', listener: (event: KeyboardEvent, + on(event: 'double-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - once(event: 'double-click', listener: (event: KeyboardEvent, + once(event: 'double-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - addListener(event: 'double-click', listener: (event: KeyboardEvent, + addListener(event: 'double-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - removeListener(event: 'double-click', listener: (event: KeyboardEvent, + removeListener(event: 'double-click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5432,22 +4965,22 @@ declare namespace Electron { /** * Emitted when the mouse enters the tray icon. */ - on(event: 'mouse-enter', listener: (event: KeyboardEvent, + on(event: 'mouse-enter', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - once(event: 'mouse-enter', listener: (event: KeyboardEvent, + once(event: 'mouse-enter', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - addListener(event: 'mouse-enter', listener: (event: KeyboardEvent, + addListener(event: 'mouse-enter', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - removeListener(event: 'mouse-enter', listener: (event: KeyboardEvent, + removeListener(event: 'mouse-enter', listener: (event: Event, /** * The position of the event. */ @@ -5455,22 +4988,22 @@ declare namespace Electron { /** * Emitted when the mouse exits the tray icon. */ - on(event: 'mouse-leave', listener: (event: KeyboardEvent, + on(event: 'mouse-leave', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - once(event: 'mouse-leave', listener: (event: KeyboardEvent, + once(event: 'mouse-leave', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - addListener(event: 'mouse-leave', listener: (event: KeyboardEvent, + addListener(event: 'mouse-leave', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - removeListener(event: 'mouse-leave', listener: (event: KeyboardEvent, + removeListener(event: 'mouse-leave', listener: (event: Event, /** * The position of the event. */ @@ -5478,22 +5011,22 @@ declare namespace Electron { /** * Emitted when the mouse moves in the tray icon. */ - on(event: 'mouse-move', listener: (event: KeyboardEvent, + on(event: 'mouse-move', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - once(event: 'mouse-move', listener: (event: KeyboardEvent, + once(event: 'mouse-move', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - addListener(event: 'mouse-move', listener: (event: KeyboardEvent, + addListener(event: 'mouse-move', listener: (event: Event, /** * The position of the event. */ position: Point) => void): this; - removeListener(event: 'mouse-move', listener: (event: KeyboardEvent, + removeListener(event: 'mouse-move', listener: (event: Event, /** * The position of the event. */ @@ -5501,22 +5034,22 @@ declare namespace Electron { /** * Emitted when the tray icon is right clicked. */ - on(event: 'right-click', listener: (event: KeyboardEvent, + on(event: 'right-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - once(event: 'right-click', listener: (event: KeyboardEvent, + once(event: 'right-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - addListener(event: 'right-click', listener: (event: KeyboardEvent, + addListener(event: 'right-click', listener: (event: Event, /** * The bounds of tray icon. */ bounds: Rectangle) => void): this; - removeListener(event: 'right-click', listener: (event: KeyboardEvent, + removeListener(event: 'right-click', listener: (event: Event, /** * The bounds of tray icon. */ @@ -5535,7 +5068,6 @@ declare namespace Electron { */ getBounds(): Rectangle; getIgnoreDoubleClickEvents(): boolean; - getTitle(title: string): string; isDestroyed(): boolean; /** * Pops up the context menu of the tray icon. When menu is passed, the menu will be @@ -5548,9 +5080,9 @@ declare namespace Electron { */ setContextMenu(menu: (Menu) | (null)): void; /** - * Sets when the tray's icon background becomes highlighted (in blue). Deprecated - * Note: You can use highlightMode with a BrowserWindow by toggling between 'never' - * and 'always' modes when the window visibility changes. + * Sets when the tray's icon background becomes highlighted (in blue). Note: You + * can use highlightMode with a BrowserWindow by toggling between 'never' and + * 'always' modes when the window visibility changes. */ setHighlightMode(mode: 'selection' | 'always' | 'never'): void; /** @@ -5568,7 +5100,7 @@ declare namespace Electron { */ setPressedImage(image: (NativeImage) | (string)): void; /** - * Sets the title displayed next to the tray icon in the status bar (Support ANSI + * Sets the title displayed aside of the tray icon in the status bar (Support ANSI * colors). */ setTitle(title: string): void; @@ -5836,14 +5368,6 @@ declare namespace Electron { * coordinates of the custom cursor's hotspot. */ hotspot?: Point) => void): this; - /** - * Emitted when desktopCapturer.getSources() is called in the renderer process. - * Calling event.preventDefault() will make it return empty sources. - */ - on(event: 'desktop-capturer-get-sources', listener: (event: Event) => void): this; - once(event: 'desktop-capturer-get-sources', listener: (event: Event) => void): this; - addListener(event: 'desktop-capturer-get-sources', listener: (event: Event) => void): this; - removeListener(event: 'desktop-capturer-get-sources', listener: (event: Event) => void): this; /** * Emitted when webContents is destroyed. */ @@ -6192,13 +5716,6 @@ declare namespace Electron { once(event: 'dom-ready', listener: (event: Event) => void): this; addListener(event: 'dom-ready', listener: (event: Event) => void): this; removeListener(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Emitted when the window enters a full-screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - once(event: 'enter-html-full-screen', listener: Function): this; - addListener(event: 'enter-html-full-screen', listener: Function): this; - removeListener(event: 'enter-html-full-screen', listener: Function): this; /** * Emitted when a result is available for [webContents.findInPage] request. */ @@ -6210,45 +5727,6 @@ declare namespace Electron { result: Result) => void): this; removeListener(event: 'found-in-page', listener: (event: Event, result: Result) => void): this; - /** - * Emitted when the renderer process sends an asynchronous message via - * ipcRenderer.send(). - */ - on(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - once(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - addListener(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - removeListener(event: 'ipc-message', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - /** - * Emitted when the renderer process sends a synchronous message via - * ipcRenderer.sendSync(). - */ - on(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - once(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - addListener(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - removeListener(event: 'ipc-message-sync', listener: (event: Event, - channel: string, - ...args: any[]) => void): this; - /** - * Emitted when the window leaves a full-screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - once(event: 'leave-html-full-screen', listener: Function): this; - addListener(event: 'leave-html-full-screen', listener: Function): this; - removeListener(event: 'leave-html-full-screen', listener: Function): this; /** * Emitted when webContents wants to do basic auth. The usage is the same with the * login event of app. @@ -6463,21 +5941,6 @@ declare namespace Electron { removeListener(event: 'plugin-crashed', listener: (event: Event, name: string, version: string) => void): this; - /** - * Emitted when the preload script preloadPath throws an unhandled exception error. - */ - on(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - once(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - addListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - removeListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; /** * Emitted when remote.getBuiltin() is called in the renderer process. Calling * event.preventDefault() will prevent the module from being returned. Custom value @@ -6742,23 +6205,16 @@ declare namespace Electron { canGoBack(): boolean; canGoForward(): boolean; canGoToOffset(offset: number): boolean; - /** - * Captures a snapshot of the page within rect. Omitting rect will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise; /** * Captures a snapshot of the page within rect. Upon completion callback will be * called with callback(image). The image is an instance of NativeImage that stores * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon */ capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; /** * Captures a snapshot of the page within rect. Upon completion callback will be * called with callback(image). The image is an instance of NativeImage that stores * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon */ capturePage(callback: (image: NativeImage) => void): void; /** @@ -6805,15 +6261,12 @@ declare namespace Electron { /** * Evaluates code in page. In the browser window some HTML APIs like * requestFullScreen can only be invoked by a gesture from the user. Setting - * userGesture to true will remove this limitation. Deprecated Soon + * userGesture to true will remove this limitation. If the result of the executed + * code is a promise the callback result will be the resolved value of the promise. + * We recommend that you use the returned Promise to handle code that results in a + * Promise. */ executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Evaluates code in page. In the browser window some HTML APIs like - * requestFullScreen can only be invoked by a gesture from the user. Setting - * userGesture to true will remove this limitation. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise; /** * Starts a request to find all matches for the text in the web page. The result of * the request can be obtained by subscribing to found-in-page event. @@ -6835,8 +6288,16 @@ declare namespace Electron { getURL(): string; getUserAgent(): string; getWebRTCIPHandlingPolicy(): string; - getZoomFactor(): number; - getZoomLevel(): number; + /** + * Sends a request to get current zoom factor, the callback will be called with + * callback(zoomFactor). + */ + getZoomFactor(callback: (zoomFactor: number) => void): void; + /** + * Sends a request to get current zoom level, the callback will be called with + * callback(zoomLevel). + */ + getZoomLevel(callback: (zoomLevel: number) => void): void; /** * Makes the browser go back a web page. */ @@ -6853,6 +6314,11 @@ declare namespace Electron { * Navigates to the specified offset from the "current entry". */ goToOffset(offset: number): void; + /** + * Checks if any ServiceWorker is registered and returns a boolean as response to + * callback. + */ + hasServiceWorker(callback: (hasWorker: boolean) => void): void; /** * Injects CSS into the current web page. */ @@ -6869,10 +6335,6 @@ declare namespace Electron { * Opens the developer tools for the service worker context. */ inspectServiceWorker(): void; - /** - * Opens the developer tools for the shared worker context. - */ - inspectSharedWorker(): void; /** * Schedules a full repaint of the window this web contents is in. If offscreen * rendering is enabled invalidates the frame and generates a new one through the @@ -6896,13 +6358,13 @@ declare namespace Electron { * relative to the root of your application. For instance an app structure like * this: Would require code like this */ - loadFile(filePath: string, options?: LoadFileOptions): Promise; + loadFile(filePath: string, options?: LoadFileOptions): void; /** * Loads the url in the window. The url must contain the protocol prefix, e.g. the * http:// or file://. If the load should bypass http cache then use the pragma * header to achieve it. */ - loadURL(url: string, options?: LoadURLOptions): Promise; + loadURL(url: string, options?: LoadURLOptions): void; /** * Opens the devtools. When contents is a tag, the mode would be detach * by default, explicitly passing an empty mode can force using last used dock @@ -6925,18 +6387,13 @@ declare namespace Electron { * Use page-break-before: always; CSS style to force to print to a new page. */ print(options?: PrintOptions, callback?: (success: boolean) => void): void; - /** - * Prints window's web page as PDF with Chromium's preview printing custom - * settings. The landscape will be ignored if @page CSS at-rule is used in the web - * page. By default, an empty options will be regarded as: Use page-break-before: - * always; CSS style to force to print to a new page. An example of - * webContents.printToPDF: - */ - printToPDF(options: PrintToPDFOptions): Promise; /** * Prints window's web page as PDF with Chromium's preview printing custom * settings. The callback will be called with callback(error, data) on completion. - * The data is a Buffer that contains the generated PDF data. Deprecated Soon + * The data is a Buffer that contains the generated PDF data. The landscape will be + * ignored if @page CSS at-rule is used in the web page. By default, an empty + * options will be regarded as: Use page-break-before: always; CSS style to force + * to print to a new page. An example of webContents.printToPDF: */ printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; /** @@ -6963,7 +6420,7 @@ declare namespace Electron { * Executes the editing command replaceMisspelling in web page. */ replaceMisspelling(text: string): void; - savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'): Promise; + savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML', callback: (error: Error) => void): boolean; /** * Executes the editing command selectAll in web page. */ @@ -6984,16 +6441,6 @@ declare namespace Electron { * object also have following properties: */ sendInputEvent(event: Event): void; - /** - * Send an asynchronous message to a specific frame in a renderer process via - * channel. Arguments will be serialized as JSON internally and as such no - * functions or prototype chains will be included. The renderer process can handle - * the message by listening to channel with the ipcRenderer module. If you want to - * get the frameId of a given renderer context you should use the - * webFrame.routingId value. E.g. You can also read frameId from all incoming IPC - * messages in the main process. - */ - sendToFrame(frameId: number, channel: string, ...args: any[]): void; /** * Mute the audio on the current web page. */ @@ -7092,6 +6539,12 @@ declare namespace Electron { * Executes the editing command undo in web page. */ undo(): void; + /** + * Unregisters any ServiceWorker if present and returns a boolean as response to + * callback when the JS promise is fulfilled or false when the JS promise is + * rejected. + */ + unregisterServiceWorker(callback: (success: boolean) => void): void; /** * Executes the editing command unselect in web page. */ @@ -7121,22 +6574,11 @@ declare namespace Electron { * requestFullScreen can only be invoked by a gesture from the user. Setting * userGesture to true will remove this limitation. */ - executeJavaScript(code: string, userGesture?: boolean): Promise; - /** - * Evaluates code in page. In the browser window some HTML APIs like - * requestFullScreen can only be invoked by a gesture from the user. Setting - * userGesture to true will remove this limitation. Deprecated Soon - */ executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; /** - * Works like executeJavaScript but evaluates scripts in an isolated context. - * Deprecated Soon + * Work like executeJavaScript but evaluates scripts in an isolated context. */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Works like executeJavaScript but evaluates scripts in an isolated context. - */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean): Promise; + executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any) => void): void; findFrameByName(name: string): WebFrame; findFrameByRoutingId(routingId: number): WebFrame; getFrameForSelector(selector: string): WebFrame; @@ -7147,14 +6589,22 @@ declare namespace Electron { getResourceUsage(): ResourceUsage; getZoomFactor(): number; getZoomLevel(): number; - /** - * Inserts css as a style sheet in the document. - */ - insertCSS(css: string): void; /** * Inserts text to the focused element. */ insertText(text: string): void; + /** + * Resources will be loaded from this scheme regardless of the current page's + * Content Security Policy. + */ + registerURLSchemeAsBypassingCSP(scheme: string): void; + /** + * Registers the scheme as secure, bypasses content security policy for resources, + * allows registering ServiceWorker and supports fetch API. Specify an option with + * the value of false to omit it from the registration. An example of registering a + * privileged scheme, without bypassing Content Security Policy: + */ + registerURLSchemeAsPrivileged(scheme: string, options?: RegisterURLSchemeAsPrivilegedOptions): void; /** * Set the content security policy of the isolated world. */ @@ -7163,11 +6613,6 @@ declare namespace Electron { * Set the name of the isolated world. Useful in devtools. */ setIsolatedWorldHumanReadableName(worldId: number, name: string): void; - /** - * Set the security origin, content security policy and name of the isolated world. - * Note: If the csp is specified, then the securityOrigin also has to be specified. - */ - setIsolatedWorldInfo(worldId: number, info: Info): void; /** * Set the security origin of the isolated world. */ @@ -7178,12 +6623,10 @@ declare namespace Electron { setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; /** * Sets a provider for spell checking in input fields and text areas. The provider - * must be an object that has a spellCheck method that accepts an array of - * individual words for spellchecking. The spellCheck function runs asynchronously - * and calls the callback function with an array of misspelt words when complete. - * An example of using node-spellchecker as provider: + * must be an object that has a spellCheck method that returns whether the word + * passed is correctly spelled. An example of using node-spellchecker as provider: */ - setSpellCheckProvider(language: string, provider: Provider): void; + setSpellCheckProvider(language: string, autoCorrectWord: boolean, provider: Provider): void; /** * Sets the maximum and minimum pinch-to-zoom level. */ @@ -7242,90 +6685,90 @@ declare namespace Electron { * The listener will be called with listener(details) when a server initiated * redirect is about to occur. */ - onBeforeRedirect(listener: ((details: OnBeforeRedirectDetails) => void) | (null)): void; + onBeforeRedirect(listener: (details: OnBeforeRedirectDetails) => void): void; /** * The listener will be called with listener(details) when a server initiated * redirect is about to occur. */ - onBeforeRedirect(filter: OnBeforeRedirectFilter, listener: ((details: OnBeforeRedirectDetails) => void) | (null)): void; + onBeforeRedirect(filter: OnBeforeRedirectFilter, listener: (details: OnBeforeRedirectDetails) => void): void; /** * The listener will be called with listener(details, callback) when a request is * about to occur. The uploadData is an array of UploadData objects. The callback - * has to be called with an response object. Some examples of valid urls: + * has to be called with an response object. */ - onBeforeRequest(listener: ((details: OnBeforeRequestDetails, callback: (response: Response) => void) => void) | (null)): void; + onBeforeRequest(listener: (details: OnBeforeRequestDetails, callback: (response: Response) => void) => void): void; /** * The listener will be called with listener(details, callback) when a request is * about to occur. The uploadData is an array of UploadData objects. The callback - * has to be called with an response object. Some examples of valid urls: + * has to be called with an response object. */ - onBeforeRequest(filter: OnBeforeRequestFilter, listener: ((details: OnBeforeRequestDetails, callback: (response: Response) => void) => void) | (null)): void; + onBeforeRequest(filter: OnBeforeRequestFilter, listener: (details: OnBeforeRequestDetails, callback: (response: Response) => void) => void): void; /** * The listener will be called with listener(details, callback) before sending an * HTTP request, once the request headers are available. This may occur after a TCP * connection is made to the server, but before any http data is sent. The callback * has to be called with an response object. */ - onBeforeSendHeaders(filter: OnBeforeSendHeadersFilter, listener: ((details: OnBeforeSendHeadersDetails, callback: (response: OnBeforeSendHeadersResponse) => void) => void) | (null)): void; + onBeforeSendHeaders(filter: OnBeforeSendHeadersFilter, listener: (details: OnBeforeSendHeadersDetails, callback: (response: OnBeforeSendHeadersResponse) => void) => void): void; /** * The listener will be called with listener(details, callback) before sending an * HTTP request, once the request headers are available. This may occur after a TCP * connection is made to the server, but before any http data is sent. The callback * has to be called with an response object. */ - onBeforeSendHeaders(listener: ((details: OnBeforeSendHeadersDetails, callback: (response: OnBeforeSendHeadersResponse) => void) => void) | (null)): void; + onBeforeSendHeaders(listener: (details: OnBeforeSendHeadersDetails, callback: (response: OnBeforeSendHeadersResponse) => void) => void): void; /** * The listener will be called with listener(details) when a request is completed. */ - onCompleted(filter: OnCompletedFilter, listener: ((details: OnCompletedDetails) => void) | (null)): void; + onCompleted(filter: OnCompletedFilter, listener: (details: OnCompletedDetails) => void): void; /** * The listener will be called with listener(details) when a request is completed. */ - onCompleted(listener: ((details: OnCompletedDetails) => void) | (null)): void; + onCompleted(listener: (details: OnCompletedDetails) => void): void; /** * The listener will be called with listener(details) when an error occurs. */ - onErrorOccurred(listener: ((details: OnErrorOccurredDetails) => void) | (null)): void; + onErrorOccurred(listener: (details: OnErrorOccurredDetails) => void): void; /** * The listener will be called with listener(details) when an error occurs. */ - onErrorOccurred(filter: OnErrorOccurredFilter, listener: ((details: OnErrorOccurredDetails) => void) | (null)): void; + onErrorOccurred(filter: OnErrorOccurredFilter, listener: (details: OnErrorOccurredDetails) => void): void; /** * The listener will be called with listener(details, callback) when HTTP response * headers of a request have been received. The callback has to be called with an * response object. */ - onHeadersReceived(filter: OnHeadersReceivedFilter, listener: ((details: OnHeadersReceivedDetails, callback: (response: OnHeadersReceivedResponse) => void) => void) | (null)): void; + onHeadersReceived(filter: OnHeadersReceivedFilter, listener: (details: OnHeadersReceivedDetails, callback: (response: OnHeadersReceivedResponse) => void) => void): void; /** * The listener will be called with listener(details, callback) when HTTP response * headers of a request have been received. The callback has to be called with an * response object. */ - onHeadersReceived(listener: ((details: OnHeadersReceivedDetails, callback: (response: OnHeadersReceivedResponse) => void) => void) | (null)): void; + onHeadersReceived(listener: (details: OnHeadersReceivedDetails, callback: (response: OnHeadersReceivedResponse) => void) => void): void; /** * The listener will be called with listener(details) when first byte of the * response body is received. For HTTP requests, this means that the status line * and response headers are available. */ - onResponseStarted(listener: ((details: OnResponseStartedDetails) => void) | (null)): void; + onResponseStarted(listener: (details: OnResponseStartedDetails) => void): void; /** * The listener will be called with listener(details) when first byte of the * response body is received. For HTTP requests, this means that the status line * and response headers are available. */ - onResponseStarted(filter: OnResponseStartedFilter, listener: ((details: OnResponseStartedDetails) => void) | (null)): void; + onResponseStarted(filter: OnResponseStartedFilter, listener: (details: OnResponseStartedDetails) => void): void; /** * The listener will be called with listener(details) just before a request is * going to be sent to the server, modifications of previous onBeforeSendHeaders * response are visible by the time this listener is fired. */ - onSendHeaders(filter: OnSendHeadersFilter, listener: ((details: OnSendHeadersDetails) => void) | (null)): void; + onSendHeaders(filter: OnSendHeadersFilter, listener: (details: OnSendHeadersDetails) => void): void; /** * The listener will be called with listener(details) just before a request is * going to be sent to the server, modifications of previous onBeforeSendHeaders * response are visible by the time this listener is fired. */ - onSendHeaders(listener: ((details: OnSendHeadersDetails) => void) | (null)): void; + onSendHeaders(listener: (details: OnSendHeadersDetails) => void): void; } interface WebSource { @@ -7520,24 +6963,15 @@ declare namespace Electron { canGoForward(): boolean; canGoToOffset(offset: number): boolean; /** - * Captures a snapshot of the page within rect. Upon completion callback will be - * called with callback(image). The image is an instance of NativeImage that stores - * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon + * Captures a snapshot of the webview's page. Same as + * webContents.capturePage([rect, ]callback). */ capturePage(callback: (image: NativeImage) => void): void; /** - * Captures a snapshot of the page within rect. Upon completion callback will be - * called with callback(image). The image is an instance of NativeImage that stores - * data of the snapshot. Omitting rect will capture the whole visible page. - * Deprecated Soon + * Captures a snapshot of the webview's page. Same as + * webContents.capturePage([rect, ]callback). */ capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * Captures a snapshot of the page within rect. Omitting rect will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise; /** * Clears the navigation history. */ @@ -7562,18 +6996,12 @@ declare namespace Electron { * Initiates a download of the resource at url without navigating. */ downloadURL(url: string): void; - /** - * Evaluates code in page. If userGesture is set, it will create the user gesture - * context in the page. HTML APIs like requestFullScreen, which require user - * action, can take advantage of this option for automation. Deprecated Soon - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; /** * Evaluates code in page. If userGesture is set, it will create the user gesture * context in the page. HTML APIs like requestFullScreen, which require user * action, can take advantage of this option for automation. */ - executeJavaScript(code: string, userGesture?: boolean): Promise; + executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): void; /** * Starts a request to find all matches for the text in the web page. The result of * the request can be obtained by subscribing to found-in-page event. @@ -7587,9 +7015,16 @@ declare namespace Electron { * is disabled. */ getWebContents(): WebContents; - getWebContentsId(): number; - getZoomFactor(): number; - getZoomLevel(): number; + /** + * Sends a request to get current zoom factor, the callback will be called with + * callback(zoomFactor). + */ + getZoomFactor(callback: (zoomFactor: number) => void): void; + /** + * Sends a request to get current zoom level, the callback will be called with + * callback(zoomLevel). + */ + getZoomLevel(callback: (zoomLevel: number) => void): void; /** * Makes the guest page go back. */ @@ -7622,10 +7057,6 @@ declare namespace Electron { * Opens the DevTools for the service worker context present in the guest page. */ inspectServiceWorker(): void; - /** - * Opens the DevTools for the shared worker context present in the guest page. - */ - inspectSharedWorker(): void; isAudioMuted(): boolean; isCrashed(): boolean; isCurrentlyAudible(): boolean; @@ -7638,7 +7069,7 @@ declare namespace Electron { * Loads the url in the webview, the url must contain the protocol prefix, e.g. the * http:// or file://. */ - loadURL(url: string, options?: LoadURLOptions): Promise; + loadURL(url: string, options?: LoadURLOptions): void; /** * Opens a DevTools window for guest page. */ @@ -7657,13 +7088,9 @@ declare namespace Electron { print(options?: PrintOptions): void; /** * Prints webview's web page as PDF, Same as webContents.printToPDF(options, - * callback). Deprecated Soon + * callback). */ printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; - /** - * Prints webview's web page as PDF, Same as webContents.printToPDF(options). - */ - printToPDF(options: PrintToPDFOptions): Promise; /** * Executes editing command redo in page. */ @@ -7753,6 +7180,14 @@ declare namespace Electron { * windows. Popups are disabled by default. */ // allowpopups?: string; ### VSCODE CHANGE (https://github.com/electron/electron/blob/master/docs/tutorial/security.md) ### + /** + * When this attribute is present the webview container will automatically resize + * within the bounds specified by the attributes minwidth, minheight, maxwidth, and + * maxheight. These constraints do not impact the webview unless autosize is + * enabled. When autosize is enabled, the webview container size cannot be less + * than the minimum values or greater than the maximum. + */ + autosize?: string; /** * A list of strings which specifies the blink features to be disabled separated by * ,. The full list of supported feature strings can be found in the @@ -7772,7 +7207,7 @@ declare namespace Electron { enableblinkfeatures?: string; /** * When this attribute is false the guest page in webview will not have access to - * the remote module. The remote module is available by default. + * the remote module. The remote module is avaiable by default. */ enableremotemodule?: string; /** @@ -7785,13 +7220,6 @@ declare namespace Electron { * system resources. Node integration is disabled by default in the guest page. */ nodeintegration?: string; - /** - * Experimental option for enabling NodeJS support in sub-frames such as iframes - * inside the webview. All your preloads will load for every iframe, you can use - * process.isMainFrame to determine if you are in the main frame or not. This - * option is disabled by default in the guest page. - */ - nodeintegrationinsubframes?: string; /** * Sets the session used by the page. If partition starts with persist:, the page * will use a persistent session available to all pages in the app with the same @@ -7853,23 +7281,14 @@ declare namespace Electron { * Copyright information. */ copyright?: string; - /** - * The app's build version number. - */ - version?: string; /** * Credit information. */ credits?: string; /** - * The app's website. + * The app's build version number. */ - website?: string; - /** - * Path to the app's icon. Will be shown as 64x64 pixels while retaining aspect - * ratio. - */ - iconPath?: string; + version?: string; } interface AddRepresentationOptions { @@ -7895,24 +7314,6 @@ declare namespace Electron { dataURL?: string; } - interface AnimationSettings { - /** - * Returns true if rich animations should be rendered. Looks at session type (e.g. - * remote desktop) and accessibility settings to give guidance for heavy - * animations. - */ - shouldRenderRichAnimation: boolean; - /** - * Determines on a per-platform basis whether scroll animations (e.g. produced by - * home/end key) should be enabled. - */ - scrollAnimationsEnabledBySystem: boolean; - /** - * Determines whether the user desires reduced motion based on platform APIs. - */ - prefersReducedMotion: boolean; - } - interface AppDetailsOptions { /** * Window's . It has to be set, otherwise the other options will have no effect. @@ -7956,16 +7357,6 @@ declare namespace Electron { * by default. */ height: boolean; - /** - * If true, the view's x position and width will grow and shrink proportionly with - * the window. false by default. - */ - horizontal: boolean; - /** - * If true, the view's y position and height will grow and shrink proportinaly with - * the window. false by default. - */ - vertical: boolean; } interface BitmapOptions { @@ -8084,9 +7475,7 @@ declare namespace Electron { */ kiosk?: boolean; /** - * Default window title. Default is "Electron". If the HTML tag is defined - * in the HTML file loaded by loadURL(), this property will be - * ignored. + * Default window title. Default is "Electron". */ title?: string; /** @@ -8131,8 +7520,8 @@ declare namespace Electron { enableLargerThanScreen?: boolean; /** * Window's background color as a hexadecimal value, like #66CD00 or #FFF or - * #80FFFFFF (alpha in #AARRGGBB format is supported if transparent is set to - * true). Default is #FFF (white). + * #80FFFFFF (alpha is supported if transparent is set to true). Default is #FFF + * (white). */ backgroundColor?: string; /** @@ -8244,24 +7633,15 @@ declare namespace Electron { interface CommandLine { /** * Append a switch (with optional value) to Chromium's command line. Note: This - * will not affect process.argv. The intended usage of this function is to control - * Chromium's behavior. + * will not affect process.argv, and is mainly used by developers to control some + * low-level Chromium behaviors. */ appendSwitch: (the_switch: string, value?: string) => void; /** * Append an argument to Chromium's command line. The argument will be quoted - * correctly. Switches will precede arguments regardless of appending order. If - * you're appending an argument like --switch=value, consider using - * appendSwitch('switch', 'value') instead. Note: This will not affect - * process.argv. The intended usage of this function is to control Chromium's - * behavior. + * correctly. Note: This will not affect process.argv. */ appendArgument: (value: string) => void; - hasSwitch: (the_switch: string) => boolean; - /** - * Note: When the switch is not present or has no value, it returns empty string. - */ - getSwitchValue: (the_switch: string) => string; } interface Config { @@ -8398,15 +7778,6 @@ declare namespace Electron { crashesDirectory?: string; } - interface CreateFromBitmapOptions { - width: number; - height: number; - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - interface CreateFromBufferOptions { /** * Required for bitmap buffers. @@ -8479,7 +7850,8 @@ declare namespace Electron { */ value?: string; /** - * The domain of the cookie. Empty by default if omitted. + * The domain of the cookie; this will be normalized with a preceding dot so that + * it's also valid for subdomains. Empty by default if omitted. */ domain?: string; /** @@ -8563,13 +7935,15 @@ declare namespace Electron { * Hides the dock icon. */ hide: () => void; - show: () => Promise; + /** + * Shows the dock icon. + */ + show: () => void; isVisible: () => boolean; /** * Sets the application's dock menu. */ setMenu: (menu: Menu) => void; - getMenu: () => (Menu) | (null); /** * Sets the image associated with this dock icon. */ @@ -8720,21 +8094,6 @@ declare namespace Electron { password: string; } - interface Info { - /** - * Security origin for the isolated world. - */ - securityOrigin?: string; - /** - * Content Security Policy for the isolated world. - */ - csp?: string; - /** - * Name for isolated world. Useful in devtools. - */ - name?: string; - } - interface Input { /** * Either keyUp or keyDown. @@ -8929,18 +8288,12 @@ declare namespace Electron { * Will be called with click(menuItem, browserWindow, event) when the menu item is * clicked. */ - click?: (menuItem: MenuItem, browserWindow: BrowserWindow, event: KeyboardEvent) => void; + click?: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event) => void; /** - * Can be undo, redo, cut, copy, paste, pasteAndMatchStyle, delete, selectAll, - * reload, forceReload, toggleDevTools, resetZoom, zoomIn, zoomOut, - * togglefullscreen, window, minimize, close, help, about, services, hide, - * hideOthers, unhide, quit, startSpeaking, stopSpeaking, close, minimize, zoom, - * front, appMenu, fileMenu, editMenu, viewMenu, recentDocuments, toggleTabBar, - * selectNextTab, selectPreviousTab, mergeAllWindows, clearRecentDocuments, - * moveTabToNewWindow or windowMenu Define the action of the menu item, when - * specified the click property will be ignored. See . + * Define the action of the menu item, when specified the click property will be + * ignored. See . */ - role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'startSpeaking' | 'stopSpeaking' | 'close' | 'minimize' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); + role?: string; /** * Can be normal, separator, submenu, checkbox or radio. */ @@ -8953,11 +8306,6 @@ declare namespace Electron { * If false, the menu item will be greyed out and unclickable. */ enabled?: boolean; - /** - * default is true, and when false will prevent the accelerator from triggering the - * item if the item is not visible`. - */ - acceleratorWorksWhenHidden?: boolean; /** * If false, the menu item will be entirely hidden. */ @@ -9073,82 +8421,6 @@ declare namespace Electron { normalizeAccessKeys?: boolean; } - interface MessageBoxReturnValue { - /** - * The index of the clicked button. - */ - response: number; - /** - * The checked state of the checkbox if checkboxLabel was set. Otherwise false. - */ - checkboxChecked: boolean; - } - - interface MessageBoxSyncOptions { - /** - * Can be "none", "info", "error", "question" or "warning". On Windows, "question" - * displays the same icon as "info", unless you set an icon using the "icon" - * option. On macOS, both "warning" and "error" display the same warning icon. - */ - type?: string; - /** - * Array of texts for buttons. On Windows, an empty array will result in one button - * labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when - * the message box opens. - */ - defaultId?: number; - /** - * Title of the message box, some platforms will not show it. - */ - title?: string; - /** - * Content of the message box. - */ - message: string; - /** - * Extra information of the message. - */ - detail?: string; - /** - * If provided, the message box will include a checkbox with the given label. The - * checkbox state can be inspected only when using callback. - */ - checkboxLabel?: string; - /** - * Initial checked state of the checkbox. false by default. - */ - checkboxChecked?: boolean; - icon?: (NativeImage) | (string); - /** - * The index of the button to be used to cancel the dialog, via the Esc key. By - * default this is assigned to the first button with "cancel" or "no" as the label. - * If no such labeled buttons exist and this option is not set, 0 will be used as - * the return value or callback response. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the buttons are common - * buttons (like "Cancel" or "Yes"), and show the others as command links in the - * dialog. This can make the dialog appear in the style of modern Windows apps. If - * you don't like this behavior, you can set noLink to true. - */ - noLink?: boolean; - /** - * Normalize the keyboard access keys across platforms. Default is false. Enabling - * this assumes & is used in the button labels for the placement of the keyboard - * shortcut access key and labels will be converted so they work correctly on each - * platform, & characters are removed on macOS, converted to _ on Linux, and left - * untouched on Windows. For example, a button label of Vie&w will be converted to - * Vie_w on Linux and View on macOS and can be selected via Alt-W on Windows and - * Linux. - */ - normalizeAccessKeys?: boolean; - } - interface NewWindowEvent extends Event { url: string; frameName: string; @@ -9216,7 +8488,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; redirectURL: string; statusCode: number; @@ -9242,7 +8513,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; uploadData: UploadData[]; } @@ -9261,7 +8531,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; requestHeaders: RequestHeaders; } @@ -9310,7 +8579,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; fromCache: boolean; /** @@ -9333,7 +8601,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; statusLine: string; statusCode: number; @@ -9367,7 +8634,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; responseHeaders: ResponseHeaders; /** @@ -9392,7 +8658,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; requestHeaders: RequestHeaders; } @@ -9412,11 +8677,6 @@ declare namespace Electron { * back. In detach mode it's not. */ mode: ('right' | 'bottom' | 'undocked' | 'detach'); - /** - * Whether to bring the opened devtools window to the foreground. The default is - * true. - */ - activate?: boolean; } interface OpenDialogOptions { @@ -9443,44 +8703,6 @@ declare namespace Electron { securityScopedBookmarks?: boolean; } - interface OpenDialogReturnValue { - /** - * An array of file paths chosen by the user. If the dialog is cancelled this will - * be an empty array. - */ - filePaths?: string[]; - /** - * An array matching the filePaths array of base64 encoded strings which contains - * security scoped bookmark data. securityScopedBookmarks must be enabled for this - * to be populated. - */ - bookmarks?: string[]; - } - - interface OpenDialogSyncOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Contains which features the dialog should use. The following values are - * supported: - */ - properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'>; - /** - * Message to display above input boxes. - */ - message?: string; - /** - * Create when packaged for the Mac App Store. - */ - securityScopedBookmarks?: boolean; - } - interface OpenExternalOptions { /** * true to bring the opened application to the foreground. The default is true. @@ -9492,17 +8714,6 @@ declare namespace Electron { workingDirectory?: string; } - interface OpenExternalSyncOptions { - /** - * true to bring the opened application to the foreground. The default is true. - */ - activate?: boolean; - /** - * The working directory. - */ - workingDirectory?: string; - } - interface PageFaviconUpdatedEvent extends Event { /** * Array of URLs. @@ -9663,31 +8874,21 @@ declare namespace Electron { landscape?: boolean; } - interface Privileges { + interface ProcessMemoryInfo { /** - * Default false. + * and The amount of memory currently pinned to actual physical RAM in Kilobytes. */ - standard?: boolean; + residentSet: number; /** - * Default false. + * The amount of memory not shared by other processes, such as JS heap or HTML + * content in Kilobytes. */ - secure?: boolean; + private: number; /** - * Default false. + * The amount of memory shared between processes, typically memory consumed by the + * Electron code itself in Kilobytes. */ - bypassCSP?: boolean; - /** - * Default false. - */ - allowServiceWorkers?: boolean; - /** - * Default false. - */ - supportFetchAPI?: boolean; - /** - * Default false. - */ - corsEnabled?: boolean; + shared: number; } interface ProgressBarOptions { @@ -9699,9 +8900,9 @@ declare namespace Electron { interface Provider { /** - * . + * Returns Boolean. */ - spellCheck: (words: string[], callback: (misspeltWords: string[]) => void) => void; + spellCheck: (text: string) => void; } interface ReadBookmark { @@ -9738,6 +8939,13 @@ declare namespace Electron { uploadData: UploadData[]; } + interface RegisterStandardSchemesOptions { + /** + * true to register the scheme as secure. Default false. + */ + secure?: boolean; + } + interface RegisterStreamProtocolRequest { url: string; headers: Headers; @@ -9753,6 +8961,29 @@ declare namespace Electron { uploadData: UploadData[]; } + interface RegisterURLSchemeAsPrivilegedOptions { + /** + * Default true. + */ + secure?: boolean; + /** + * Default true. + */ + bypassCSP?: boolean; + /** + * Default true. + */ + allowServiceWorkers?: boolean; + /** + * Default true. + */ + supportFetchAPI?: boolean; + /** + * Default true. + */ + corsEnabled?: boolean; + } + interface RelaunchOptions { args?: string[]; execPath?: string; @@ -9849,53 +9080,6 @@ declare namespace Electron { securityScopedBookmarks?: boolean; } - interface SaveDialogReturnValue { - /** - * whether or not the dialog was canceled. - */ - canceled: boolean; - /** - * If the dialog is canceled this will be undefined. - */ - filePath?: string; - /** - * Base64 encoded string which contains the security scoped bookmark data for the - * saved file. securityScopedBookmarks must be enabled for this to be present. - */ - bookmark?: string; - } - - interface SaveDialogSyncOptions { - title?: string; - /** - * Absolute directory path, absolute file path, or file name to use by default. - */ - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Message to display above text fields. - */ - message?: string; - /** - * Custom label for the text displayed in front of the filename text field. - */ - nameFieldLabel?: string; - /** - * Show the tags input box, defaults to true. - */ - showsTagField?: boolean; - /** - * Create a when packaged for the Mac App Store. If this option is enabled and the - * file doesn't already exist a blank file will be created at the chosen path. - */ - securityScopedBookmarks?: boolean; - } - interface Settings { /** * true to open the app at login, false to remove the app as a login item. Defaults @@ -9928,17 +9112,14 @@ declare namespace Electron { types: string[]; /** * The size that the media source thumbnail should be scaled to. Default is 150 x - * 150. Set width or height to 0 when you do not need the thumbnails. This will - * save the processing time required for capturing the content of each window and - * screen. + * 150. */ thumbnailSize?: Size; - /** - * Set to true to enable fetching window icons. The default value is false. When - * false the appIcon property of the sources return null. Same if a source has the - * type screen. - */ - fetchWindowIcons?: boolean; + } + + interface StartMonitoringOptions { + categoryFilter: string; + traceOptions: string; } interface SystemMemoryInfo { @@ -10306,7 +9487,7 @@ declare namespace Electron { */ devTools?: boolean; /** - * Whether node integration is enabled. Default is false. + * Whether node integration is enabled. Default is true. */ nodeIntegration?: boolean; /** @@ -10314,12 +9495,6 @@ declare namespace Electron { * this can be found in . */ nodeIntegrationInWorker?: boolean; - /** - * Experimental option for enabling Node.js support in sub-frames such as iframes - * and child windows. All your preloads will load for every iframe, you can use - * process.isMainFrame to determine if you are in the main frame or not. - */ - nodeIntegrationInSubFrames?: boolean; /** * Specifies a script that will be loaded before other scripts run in the page. * This script will always have access to node APIs no matter whether node @@ -10396,6 +9571,10 @@ declare namespace Electron { * Enables WebGL support. Default is true. */ webgl?: boolean; + /** + * Enables WebAudio support. Default is true. + */ + webaudio?: boolean; /** * Whether plugins should be enabled. Default is false. */ @@ -10463,17 +9642,19 @@ declare namespace Electron { */ contextIsolation?: boolean; /** - * Whether to use native window.open(). Defaults to false. Child windows will - * always have node integration disabled unless nodeIntegrationInSubFrames is true. - * This option is currently experimental. + * Whether to use native window.open(). If set to true, the webPreferences of child + * window will always be the same with parent window, regardless of the parameters + * passed to window.open(). Defaults to false. This option is currently + * experimental. */ nativeWindowOpen?: boolean; /** - * Whether to enable the . Defaults to false. The preload script configured for the - * will have node integration enabled when it is executed so you should ensure - * remote/untrusted content is not able to create a tag with a possibly malicious - * preload script. You can use the will-attach-webview event on to strip away the - * preload script and to validate or alter the 's initial settings. + * Whether to enable the . Defaults to the value of the nodeIntegration option. The + * preload script configured for the will have node integration enabled when it is + * executed so you should ensure remote/untrusted content is not able to create a + * tag with a possibly malicious preload script. You can use the + * will-attach-webview event on to strip away the preload script and to validate or + * alter the 's initial settings. */ webviewTag?: boolean; /** @@ -10497,17 +9678,6 @@ declare namespace Electron { * Default is false. */ navigateOnDragDrop?: boolean; - /** - * Autoplay policy to apply to content in the window, can be - * no-user-gesture-required, user-gesture-required, - * document-user-activation-required. Defaults to no-user-gesture-required. - */ - autoplayPolicy?: ('no-user-gesture-required' | 'user-gesture-required' | 'document-user-activation-required'); - /** - * Whether to prevent the window from resizing when entering HTML Fullscreen. - * Default is false. - */ - disableHtmlFullscreenWindowResize?: boolean; } interface DefaultFontFamily { @@ -10580,6 +9750,7 @@ declare namespace NodeJS { // addListener(event: 'loaded', listener: Function): this; // removeListener(event: 'loaded', listener: Function): this; // ### END VSCODE MODIFICATION ### + /** * Causes the main thread of the current process crash. */ @@ -10606,17 +9777,12 @@ declare namespace NodeJS { * private memory is more representative of the actual pre-compression memory usage * of the process on macOS. */ - getProcessMemoryInfo(): Promise; + getProcessMemoryInfo(): Electron.ProcessMemoryInfo; /** * Returns an object giving memory usage statistics about the entire system. Note * that all statistics are reported in Kilobytes. */ getSystemMemoryInfo(): Electron.SystemMemoryInfo; - /** - * Examples: Note: It returns the actual operating system version instead of kernel - * version on macOS unlike os.release(). - */ - getSystemVersion(): string; /** * Causes the main thread of the current process hang. */ @@ -10635,17 +9801,6 @@ declare namespace NodeJS { * this property is true in the main process, otherwise it is undefined. */ defaultApp?: boolean; - /** - * A Boolean that controls whether or not deprecation warnings are printed to - * stderr when formerly callback-based APIs converted to Promises are invoked using - * callbacks. Setting this to true will enable deprecation warnings. - */ - enablePromiseAPIs?: boolean; - /** - * A Boolean, true when the current renderer context is the "main" renderer frame. - * If you want the ID of the current frame you should use webFrame.routingId. - */ - isMainFrame?: boolean; /** * A Boolean. For Mac App Store build, this property is true, for other builds it * is undefined. @@ -10693,7 +9848,7 @@ declare namespace NodeJS { traceProcessWarnings?: boolean; /** * A String representing the current process's type, can be "browser" (i.e. main - * process), "renderer", or "worker" (i.e. web worker). + * process) or "renderer". */ type?: string; /** diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index 7d5a9ce197..cc69129822 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import * as marked from 'vs/base/common/marked/marked'; -import * as insane from 'vs/base/common/insane/insane'; +import { insane } from 'vs/base/common/insane/insane'; import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; import { escape } from 'vs/base/common/strings'; diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index dcf767b2b1..f3e0496c56 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -152,34 +152,48 @@ export class StandardWheelEvent { this.deltaX = deltaX; if (e) { - let e1 = e; - let e2 = e; + if (e.type === 'wheel') { - // vertical delta scroll - if (typeof e1.wheelDeltaY !== 'undefined') { - this.deltaY = e1.wheelDeltaY / 120; - } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { - this.deltaY = -e2.detail / 3; - } else { - this.deltaY = -e.deltaY / 40; - } + // Modern wheel event + // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent + const ev = e; - // horizontal delta scroll - if (typeof e1.wheelDeltaX !== 'undefined') { - if (browser.isSafari && platform.isWindows) { - this.deltaX = - (e1.wheelDeltaX / 120); + if (ev.deltaMode === ev.DOM_DELTA_LINE) { + // the deltas are expressed in lines + this.deltaY = -e.deltaY; + this.deltaX = -e.deltaX; } else { - this.deltaX = e1.wheelDeltaX / 120; + this.deltaY = -e.deltaY / 40; + this.deltaX = -e.deltaX / 40; } - } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { - this.deltaX = -e.detail / 3; - } else { - this.deltaX = -e.deltaX / 40; - } - // Assume a vertical scroll if nothing else worked - if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) { - this.deltaY = e.wheelDelta / 120; + } else { + // Old (deprecated) wheel events + let e1 = e; + let e2 = e; + + // vertical delta scroll + if (typeof e1.wheelDeltaY !== 'undefined') { + this.deltaY = e1.wheelDeltaY / 120; + } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { + this.deltaY = -e2.detail / 3; + } + + // horizontal delta scroll + if (typeof e1.wheelDeltaX !== 'undefined') { + if (browser.isSafari && platform.isWindows) { + this.deltaX = - (e1.wheelDeltaX / 120); + } else { + this.deltaX = e1.wheelDeltaX / 120; + } + } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { + this.deltaX = -e.detail / 3; + } + + // Assume a vertical scroll if nothing else worked + if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) { + this.deltaY = e.wheelDelta / 120; + } } } } diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index ae39dbf3e1..ac9e47790d 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -86,15 +86,21 @@ export class Gesture extends Disposable { this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e))); } - public static addTarget(element: HTMLElement): void { + public static addTarget(element: HTMLElement): IDisposable { if (!Gesture.isTouchDevice()) { - return; + return Disposable.None; } if (!Gesture.INSTANCE) { Gesture.INSTANCE = new Gesture(); } Gesture.INSTANCE.targets.push(element); + + return { + dispose: () => { + Gesture.INSTANCE.targets = Gesture.INSTANCE.targets.filter(t => t !== element); + } + }; } @memoize diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index e7274468a8..32d626f56b 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -103,7 +103,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { render(container: HTMLElement): void { this.element = container; - Gesture.addTarget(container); + this._register(Gesture.addTarget(container)); const enableDragging = this.options && this.options.draggable; if (enableDragging) { diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index 10b14761df..63e5f26a55 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -63,7 +63,7 @@ export class Button extends Disposable { container.appendChild(this._element); - Gesture.addTarget(this._element); + this._register(Gesture.addTarget(this._element)); [DOM.EventType.CLICK, EventType.Tap].forEach(eventType => { this._register(DOM.addDisposableListener(this._element, eventType, e => { diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index 6a1aa43e71..a768840276 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -83,7 +83,7 @@ export class BaseDropdown extends ActionRunner { this._register(cleanupFn); } - Gesture.addTarget(this._label); + this._register(Gesture.addTarget(this._label)); } get element(): HTMLElement { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index f408e9cf5d..9ebe302cf6 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -236,7 +236,7 @@ export class ListView implements ISpliceable, IDisposable { this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; - Gesture.addTarget(this.rowsContainer); + this.disposables.add(Gesture.addTarget(this.rowsContainer)); this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, { alwaysConsumeMouseWheel: true, diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 4972a5d18e..693d3016b3 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -542,7 +542,7 @@ export class MouseController implements IDisposable { list.onContextMenu(this.onContextMenu, this, this.disposables); list.onMouseDblClick(this.onDoubleClick, this, this.disposables); list.onTouchStart(this.onMouseDown, this, this.disposables); - Gesture.addTarget(list.getHTMLElement()); + this.disposables.add(Gesture.addTarget(list.getHTMLElement())); } list.onMouseClick(this.onPointer, this, this.disposables); diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 4d10bb0fe5..493330e43e 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -398,7 +398,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { EventHelper.stop(e, true); this.onClick(e); })); - }, 50); + }, 100); this._register(this.runOnceToEnableMouseUp); } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index a02282c329..5b17c6a378 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -238,7 +238,7 @@ export class MenuBar extends Disposable { } })); - Gesture.addTarget(buttonElement); + this._register(Gesture.addTarget(buttonElement)); this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => { // Ignore this touch if the menu is touched if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) { @@ -322,7 +322,7 @@ export class MenuBar extends Disposable { } })); - Gesture.addTarget(buttonElement); + this._register(Gesture.addTarget(buttonElement)); this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => { // Ignore this touch if the menu is touched if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) { diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css index 2305d04890..154a225158 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css @@ -1,6 +1,6 @@ @font-face { font-family: "octicons"; - src: url("./octicons.ttf?628f71ee09945d25ba5fceb0c17f7b0f") format("truetype"); + src: url("./octicons.ttf?1829db8570ee0fa5a4bef3bb41d5f62e") format("truetype"); } .octicon, .mega-octicon { diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf index 09468d3324453a2c7e5ea5a6422fffef725ec38a..90550092a65dcf320264753b16d5ac9217e37f6e 100644 GIT binary patch delta 308 zcmeB}%JgIk(*y^RtIB-w3=F~^3=BCv8L5dWV#Ve?6GL=Z;y4`-Ol(mWyu!f1Bvz1L zT+;sK+(QP2#y1mp7|2XMW6%)KZ}XLboB0I;5Zv7UOAJPDW?{T8STCYxpq8N4qRyc1 zqJB;NhlYa2GEElE9?d^mQCi!yUTLdoPtZQ5{Xs`VCrxL8u7GZg?gKpqy#&2$`u_}U z45k>oFmy94Fg#%Rz(~kQ&uEg-7vnX?A554`L`>97EKC|qZkWcIZZLgjreo#?w3zw- z|NjBZ&CI3@Dh&Dz-V6+zql8a;dohCC#PpuYia~;bfze2gMTCz+jo7kc(_=ACgNvt5h zxTO8dxrYo4O#%~l7|669I+GF4Z}XLboB0I;5Zv4}xeZ2dW?{T8Sg)q$q*kOhO?93v77Bm0< z|384anc0*eq@iB_XF`A3; zF)HaXn%FTK$uX(}v8W+Xj`532v9oh=2Z(sC;~n9x111*h`|IiXyFn#@vcGhoGCJN3 cdj9%AX`odg` { + + test('escape', () => { + + const mds = new MarkdownString(); + + mds.appendText('# foo\n*bar*'); + + assert.equal(mds.value, '\\# foo\n\n\\*bar\\*'); + }); +}); diff --git a/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts index 98f42104ce..72ea660dd9 100644 --- a/src/vs/base/worker/defaultWorkerFactory.ts +++ b/src/vs/base/worker/defaultWorkerFactory.ts @@ -27,6 +27,7 @@ function getWorker(workerId: string, label: string): Worker | Promise { throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`); } +// ESM-comment-begin export function getWorkerBootstrapUrl(scriptPath: string, label: string): string { if (/^(http:)|(https:)|(file:)/.test(scriptPath)) { const currentUrl = String(window.location); @@ -43,6 +44,7 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string } return scriptPath + '#' + label; } +// ESM-comment-end function isPromiseLike(obj: any): obj is PromiseLike { if (typeof obj.then === 'function') { diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 0573e612f1..beb9da5e1b 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent } from 'electron'; +import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, Event as IpcMainEvent, BrowserWindow } from 'electron'; import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform'; import { WindowsManager } from 'vs/code/electron-main/windows'; import { OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows'; @@ -78,6 +78,8 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; import { assign } from 'vs/base/common/objects'; +import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; export class CodeApplication extends Disposable { @@ -85,6 +87,7 @@ export class CodeApplication extends Disposable { private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId'; private windowsMainService: IWindowsMainService | undefined; + private dialogMainService: IDialogMainService | undefined; constructor( private readonly mainIpcServer: Server, @@ -381,8 +384,7 @@ export class CodeApplication extends Disposable { } // Setup Auth Handler - const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); - this._register(authHandler); + this._register(new ProxyAuthHandler()); // Open Windows const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient)); @@ -449,6 +451,7 @@ export class CodeApplication extends Disposable { } services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv])); + services.set(IDialogMainService, new SyncDescriptor(DialogMainService)); services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess])); services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService)); @@ -503,13 +506,13 @@ export class CodeApplication extends Disposable { contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => { if (!timeout) { - if (this.windowsMainService) { - this.windowsMainService.showMessageBox({ + if (this.dialogMainService) { + this.dialogMainService.showMessageBox({ type: 'info', message: localize('trace.message', "Successfully created trace."), detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), buttons: [localize('trace.ok', "Ok")] - }, this.windowsMainService.getLastActiveWindow()); + }, withNullAsUndefined(BrowserWindow.getFocusedWindow())); } } else { this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`); @@ -580,6 +583,7 @@ export class CodeApplication extends Disposable { // Propagate to clients const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); + this.dialogMainService = accessor.get(IDialogMainService); // Create a URL handler to open file URIs in the active window const environmentService = accessor.get(IEnvironmentService); diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index 1e2909a0e4..924c649040 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { BrowserWindow, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron'; @@ -22,18 +21,21 @@ type Credentials = { password: string; }; -export class ProxyAuthHandler { +export class ProxyAuthHandler extends Disposable { _serviceBrand: undefined; private retryCount = 0; - private disposables: IDisposable[] = []; - constructor( - @IWindowsMainService private readonly windowsMainService: IWindowsMainService - ) { + constructor() { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { const onLogin = Event.fromNodeEventEmitter(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb })); - onLogin(this.onLogin, this, this.disposables); + this._register(onLogin(this.onLogin, this)); } private onLogin({ event, authInfo, cb }: LoginEvent): void { @@ -61,10 +63,9 @@ export class ProxyAuthHandler { } }; - const focusedWindow = this.windowsMainService.getFocusedWindow(); - + const focusedWindow = BrowserWindow.getFocusedWindow(); if (focusedWindow) { - opts.parent = focusedWindow.win; + opts.parent = focusedWindow; opts.modal = true; } @@ -89,8 +90,4 @@ export class ProxyAuthHandler { win.close(); }); } - - dispose(): void { - this.disposables = dispose(this.disposables); - } } diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 3dd9b7fa84..0f5f7c3028 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -7,7 +7,7 @@ import { assign } from 'vs/base/common/objects'; import { memoize } from 'vs/base/common/decorators'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { BrowserWindow, ipcMain } from 'electron'; -import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; +import { ISharedProcess } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 4aa7856093..4d82f883a3 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -561,7 +561,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { autoDetectHighContrast = false; } windowConfiguration.highContrast = isWindows && autoDetectHighContrast && systemPreferences.isInvertedColorScheme(); - windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled; + windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled(); // Title style related windowConfiguration.maximized = this._win.isMaximized(); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 21ec680735..14677b3be3 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; -import { basename, normalize, join, dirname } from 'vs/base/common/path'; +import { basename, normalize, join, } from 'vs/base/common/path'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; @@ -13,34 +13,36 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IStateService } from 'vs/platform/state/node/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; -import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron'; +import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; -import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder'; +import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window'; import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product/common/product'; import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult, IRecent } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { Schemas } from 'vs/base/common/network'; -import { normalizeNFC } from 'vs/base/common/normalization'; import { URI } from 'vs/base/common/uri'; -import { Queue } from 'vs/base/common/async'; -import { exists, dirExists } from 'vs/base/node/pfs'; -import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources'; +import { dirExists } from 'vs/base/node/pfs'; +import { getComparisonKey, isEqual, normalizePath, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; import { getWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { once } from 'vs/base/common/functional'; import { Disposable } from 'vs/base/common/lifecycle'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { isWindowsDriveLetter, toSlashes } from 'vs/base/common/extpath'; +import { CharCode } from 'vs/base/common/charCode'; const enum WindowError { UNRESPONSIVE = 1, @@ -167,9 +169,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private readonly windowsState: IWindowsState; private lastClosedWindowState?: IWindowState; - private readonly dialogs: Dialogs; - private readonly workspacesManager: WorkspacesManager; - private readonly _onWindowReady = this._register(new Emitter()); readonly onWindowReady: CommonEvent = this._onWindowReady.event; @@ -194,7 +193,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); @@ -203,9 +203,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.windowsState.openedWindows = []; } - this.dialogs = new Dialogs(stateService, this); - this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); - this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); } @@ -260,6 +257,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.lastClosedWindowState = undefined; } }); + + // Signal a window is ready after having entered a workspace + this._register(this.workspacesMainService.onWorkspaceEntered(event => { + this._onWindowReady.fire(event.window); + })); } // Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS: @@ -380,12 +382,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }; } - async openExternal(url: string): Promise { - shell.openExternal(url); - - return true; - } - open(openConfig: IOpenConfiguration): ICodeWindow[] { this.logService.trace('windowsManager#open'); openConfig = this.validateOpenConfig(openConfig); @@ -776,7 +772,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private doAddFoldersToExistingWindow(window: ICodeWindow, foldersToAdd: URI[]): ICodeWindow { window.focus(); // make sure window has focus - window.sendWhenReady('vscode:addFolders', { foldersToAdd }); + const request: IAddFoldersRequest = { foldersToAdd }; + + window.sendWhenReady('vscode:addFolders', request); return window; } @@ -862,7 +860,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { path.label = pathToOpen.label; pathsToOpen.push(path); } else { - const uri = resourceFromURIToOpen(pathToOpen); + const uri = this.resourceFromURIToOpen(pathToOpen); + // Warn about the invalid URI or path let message, detail; if (uri.scheme === Schemas.file) { @@ -881,7 +880,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { noLink: true }; - this.dialogs.showMessageBox(options, this.getFocusedWindow()); + this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow())); } } return pathsToOpen; @@ -1011,10 +1010,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.logService.error(`Invalid URI input string, scheme missing: ${arg}`); return undefined; } + return uri; } catch (e) { this.logService.error(`Invalid URI input string: ${arg}, ${e.message}`); } + return undefined; } @@ -1023,7 +1024,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return undefined; } - let uri = resourceFromURIToOpen(toOpen); + let uri = this.resourceFromURIToOpen(toOpen); if (uri.scheme === Schemas.file) { return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen)); } @@ -1050,6 +1051,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { remoteAuthority }; } + return { fileUri: uri, remoteAuthority @@ -1071,6 +1073,18 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }; } + private resourceFromURIToOpen(openable: IWindowOpenable): URI { + if (isWorkspaceToOpen(openable)) { + return openable.workspaceUri; + } + + if (isFolderToOpen(openable)) { + return openable.folderUri; + } + + return openable.fileUri; + } + private parsePath(anyPath: string, options: IPathParseOptions, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined { if (!anyPath) { return undefined; @@ -1086,11 +1100,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService { anyPath = parsedPath.path; } - // open remote if either specified in the cli even if it is a local file. TODO@aeschli: Future idea: resolve in remote host context. + // open remote if either specified in the cli even if it is a local file. const remoteAuthority = options.remoteAuthority; - const candidate = normalize(anyPath); + if (remoteAuthority) { + // assume it's a folder or workspace file + + const first = anyPath.charCodeAt(0); + // make absolute + if (first !== CharCode.Slash) { + if (isWindowsDriveLetter(first) && anyPath.charCodeAt(anyPath.charCodeAt(1)) === CharCode.Colon) { + anyPath = toSlashes(anyPath); + } + anyPath = '/' + anyPath; + } + + const uri = URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: anyPath }); + + if (hasWorkspaceFileExtension(anyPath)) { + if (forceOpenWorkspaceAsFile) { + return { fileUri: uri, remoteAuthority }; + } + return { workspace: getWorkspaceIdentifier(uri), remoteAuthority }; + } + return { folderUri: uri, remoteAuthority }; + } + + let candidate = normalize(anyPath); + try { + const candidateStat = fs.statSync(candidate); if (candidateStat.isFile()) { @@ -1185,7 +1224,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow }; } - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void { + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[] { // Reload an existing extension development host window on the same path // We currently do not allow more than one extension development window @@ -1195,7 +1234,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.reload(existingWindow, openConfig.cli); existingWindow.focus(); // make sure it gets focus and is restored - return; + return [existingWindow]; } let folderUris = openConfig.cli['folder-uri'] || []; let fileUris = openConfig.cli['file-uri'] || []; @@ -1286,7 +1325,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { noRecentEntry: true, waitMarkerFileURI: openConfig.waitMarkerFileURI }; - this.open(openArgs); + + return this.open(openArgs); } private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow { @@ -1580,23 +1620,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }); } - async enterWorkspace(win: ICodeWindow, path: URI): Promise { - const result = await this.workspacesManager.enterWorkspace(win, path); - - return result ? this.doEnterWorkspace(win, result) : undefined; - } - - private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult { - - // Mark as recently opened - this.workspacesHistoryMainService.addRecentlyOpened([{ workspace: result.workspace }]); - - // Trigger Eevent to indicate load of workspace into window - this._onWindowReady.fire(win); - - return result; - } - focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow { const lastActive = this.getLastActiveWindow(); if (lastActive) { @@ -1613,7 +1636,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return getLastActiveWindow(WindowsManager.WINDOWS); } - getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined { + private getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined { return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority)); } @@ -1623,13 +1646,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (cli && (cli.remote !== remote)) { cli = { ...cli, remote }; } - const forceReuseWindow = options && options.reuse; - const forceNewWindow = !forceReuseWindow; - return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow }); - } - openNewTabbedWindow(context: OpenContext): ICodeWindow[] { - return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true }); + const forceReuseWindow = options && options.forceReuseWindow; + const forceNewWindow = !forceReuseWindow; + + return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow }); } waitForWindowCloseOrLoad(windowId: number): Promise { @@ -1666,7 +1687,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } - getFocusedWindow(): ICodeWindow | undefined { + private getFocusedWindow(): ICodeWindow | undefined { const win = BrowserWindow.getFocusedWindow(); if (win) { return this.getWindowById(win.id); @@ -1710,14 +1731,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Show Dialog - this.dialogs.showMessageBox({ + this.dialogMainService.showMessageBox({ title: product.nameLong, type: 'warning', buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message: localize('appStalled', "The window is no longer responding"), detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."), noLink: true - }, window).then(result => { + }, window.win).then(result => { if (!window.win) { return; // Return early if the window has been going down already } @@ -1733,14 +1754,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Crashed else { - this.dialogs.showMessageBox({ + this.dialogMainService.showMessageBox({ title: product.nameLong, type: 'warning', buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], message: localize('appCrashed', "The window has crashed"), detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."), noLink: true - }, window).then(result => { + }, window.win).then(result => { if (!window.win) { return; // Return early if the window has been going down already } @@ -1770,8 +1791,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('open', "Open"); - const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title }); + const paths = await this.dialogMainService.pickFileFolder(options); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData); const urisToOpen = await Promise.all(paths.map(async path => { @@ -1790,8 +1810,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openFolder', "Open Folder"); - const paths = await this.dialogs.pick({ ...options, pickFolders: true, title }); + const paths = await this.dialogMainService.pickFolder(options); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData); this.open({ @@ -1805,8 +1824,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openFile', "Open File"); - const paths = await this.dialogs.pick({ ...options, pickFiles: true, title }); + const paths = await this.dialogMainService.pickFile(options); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData); this.open({ @@ -1820,10 +1838,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise { - const title = localize('openWorkspaceTitle', "Open Workspace"); - const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")); - const filters = WORKSPACE_FILTER; - const paths = await this.dialogs.pick({ ...options, pickFiles: true, title, filters, buttonLabel }); + const paths = await this.dialogMainService.pickWorkspace(options); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData); this.open({ @@ -1838,7 +1853,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } private sendPickerTelemetry(paths: string[], telemetryEventName: string, telemetryExtraData?: ITelemetryData) { - const numberOfPaths = paths ? paths.length : 0; // Telemetry @@ -1850,18 +1864,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }); } - showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise { - return this.dialogs.showMessageBox(options, win); - } - - showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise { - return this.dialogs.showSaveDialog(options, win); - } - - showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise { - return this.dialogs.showOpenDialog(options, win); - } - quit(): void { // If the user selected to exit from an extension development host window, do not quit, but just @@ -1879,240 +1881,3 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } } } - -interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions { - - pickFolders?: boolean; - pickFiles?: boolean; - - title: string; - buttonLabel?: string; - filters?: FileFilter[]; -} - -class Dialogs { - - private static readonly workingDirPickerStorageKey = 'pickerWorkingDir'; - - private readonly mapWindowToDialogQueue: Map>; - private readonly noWindowDialogQueue: Queue; - - constructor( - private readonly stateService: IStateService, - private readonly windowsMainService: IWindowsMainService - ) { - this.mapWindowToDialogQueue = new Map>(); - this.noWindowDialogQueue = new Queue(); - } - - async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise { - - // Ensure dialog options - const dialogOptions: OpenDialogOptions = { - title: options.title, - buttonLabel: options.buttonLabel, - filters: options.filters - }; - - // Ensure defaultPath - dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem(Dialogs.workingDirPickerStorageKey); - - - // Ensure properties - if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') { - dialogOptions.properties = undefined; // let it override based on the booleans - - if (options.pickFiles && options.pickFolders) { - dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory']; - } - } - - if (!dialogOptions.properties) { - dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory']; - } - - if (isMacintosh) { - dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files - } - - // Show Dialog - const windowToUse = win || this.windowsMainService.getFocusedWindow(); - - const result = await this.showOpenDialog(dialogOptions, windowToUse); - if (result && result.filePaths && result.filePaths.length > 0) { - - // Remember path in storage for next time - this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(result.filePaths[0])); - - return result.filePaths; - } - - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check - } - - private getDialogQueue(window?: ICodeWindow): Queue { - if (!window) { - return this.noWindowDialogQueue; - } - - let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id); - if (!windowDialogQueue) { - windowDialogQueue = new Queue(); - this.mapWindowToDialogQueue.set(window.id, windowDialogQueue); - } - - return windowDialogQueue; - } - - showMessageBox(options: MessageBoxOptions, window?: ICodeWindow): Promise { - return this.getDialogQueue(window).queue(async () => { - if (window) { - return dialog.showMessageBox(window.win, options); - } - - return dialog.showMessageBox(options); - }); - } - - showSaveDialog(options: SaveDialogOptions, window?: ICodeWindow): Promise { - - function normalizePath(path: string | undefined): string | undefined { - if (path && isMacintosh) { - path = normalizeNFC(path); // normalize paths returned from the OS - } - - return path; - } - - return this.getDialogQueue(window).queue(async () => { - let result: SaveDialogReturnValue; - if (window) { - result = await dialog.showSaveDialog(window.win, options); - } else { - result = await dialog.showSaveDialog(options); - } - - result.filePath = normalizePath(result.filePath); - - return result; - }); - } - - showOpenDialog(options: OpenDialogOptions, window?: ICodeWindow): Promise { - - function normalizePaths(paths: string[] | undefined): string[] | undefined { - if (paths && paths.length > 0 && isMacintosh) { - paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS - } - - return paths; - } - - return this.getDialogQueue(window).queue(async () => { - - // Ensure the path exists (if provided) - if (options.defaultPath) { - const pathExists = await exists(options.defaultPath); - if (!pathExists) { - options.defaultPath = undefined; - } - } - - // Show dialog - let result: OpenDialogReturnValue; - if (window) { - result = await dialog.showOpenDialog(window.win, options); - } else { - result = await dialog.showOpenDialog(options); - } - - result.filePaths = normalizePaths(result.filePaths); - - return result; - }); - } -} - -class WorkspacesManager { - - constructor( - private readonly workspacesMainService: IWorkspacesMainService, - private readonly backupMainService: IBackupMainService, - private readonly windowsMainService: IWindowsMainService, - ) { } - - async enterWorkspace(window: ICodeWindow, path: URI): Promise { - if (!window || !window.win || !window.isReady) { - return null; // return early if the window is not ready or disposed - } - - const isValid = await this.isValidTargetWorkspacePath(window, path); - if (!isValid) { - return null; // return early if the workspace is not valid - } - - return this.doOpenWorkspace(window, getWorkspaceIdentifier(path)); - } - - private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { - if (!path) { - return true; - } - - if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { - return false; // window is already opened on a workspace with that path - } - - // Prevent overwriting a workspace that is currently opened in another window - if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) { - const options: MessageBoxOptions = { - title: product.nameLong, - type: 'info', - buttons: [localize('ok', "OK")], - message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", resourcesBasename(path)), - detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), - noLink: true - }; - - await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()); - - return false; - } - - return true; // OK - } - - private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult { - window.focus(); - - // Register window for backups and migrate current backups over - let backupPath: string | undefined; - if (!window.config.extensionDevelopmentPath) { - backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath); - } - - // if the window was opened on an untitled workspace, delete it. - if (window.openedWorkspace && this.workspacesMainService.isUntitledWorkspace(window.openedWorkspace)) { - this.workspacesMainService.deleteUntitledWorkspaceSync(window.openedWorkspace); - } - - // Update window configuration properly based on transition to workspace - window.config.folderUri = undefined; - window.config.workspace = workspace; - window.config.backupPath = backupPath; - - return { workspace, backupPath }; - } -} - -function resourceFromURIToOpen(openable: IWindowOpenable): URI { - if (isWorkspaceToOpen(openable)) { - return openable.workspaceUri; - } - - if (isFolderToOpen(openable)) { - return openable.folderUri; - } - - return openable.fileUri; -} diff --git a/src/vs/code/electron-main/windowsStateStorage.ts b/src/vs/code/electron-main/windowsStateStorage.ts index 646c42910c..ef65864434 100644 --- a/src/vs/code/electron-main/windowsStateStorage.ts +++ b/src/vs/code/electron-main/windowsStateStorage.ts @@ -35,12 +35,15 @@ export function restoreWindowsState(data: WindowsStateStorageData | undefined): if (windowsState.lastActiveWindow) { result.lastActiveWindow = restoreWindowState(windowsState.lastActiveWindow); } + if (windowsState.lastPluginDevelopmentHostWindow) { result.lastPluginDevelopmentHostWindow = restoreWindowState(windowsState.lastPluginDevelopmentHostWindow); } + if (Array.isArray(windowsState.openedWindows)) { result.openedWindows = windowsState.openedWindows.map(windowState => restoreWindowState(windowState)); } + return result; } @@ -49,9 +52,11 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState { if (windowState.backupPath) { result.backupPath = windowState.backupPath; } + if (windowState.remoteAuthority) { result.remoteAuthority = windowState.remoteAuthority; } + if (windowState.folder) { result.folderUri = URI.parse(windowState.folder); } else if (windowState.folderUri) { @@ -59,11 +64,13 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState { } else if (windowState.folderPath) { result.folderUri = URI.file(windowState.folderPath); } + if (windowState.workspaceIdentifier) { result.workspace = { id: windowState.workspaceIdentifier.id, configPath: URI.parse(windowState.workspaceIdentifier.configURIPath) }; } else if (windowState.workspace) { result.workspace = { id: windowState.workspace.id, configPath: URI.file(windowState.workspace.configPath) }; } + return result; } diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index a46e1cb7c7..1a29315cf3 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -3,19 +3,18 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as os from 'os'; +import * as fs from 'fs'; import { spawn, ChildProcess, SpawnOptions } from 'child_process'; import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv'; import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/common/product'; import * as paths from 'vs/base/common/path'; -import * as os from 'os'; -import * as fs from 'fs'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { resolveTerminalEncoding } from 'vs/base/node/encoding'; -import * as iconv from 'iconv-lite'; -import { isWindows, isLinux } from 'vs/base/common/platform'; +import { isWindows } from 'vs/base/common/platform'; import { ProfilingSession, Target } from 'v8-inspect-profiler'; import { isString } from 'vs/base/common/types'; @@ -179,7 +178,8 @@ export async function main(argv: string[]): Promise { if (!stdinFileError) { // Pipe into tmp file using terminals encoding - resolveTerminalEncoding(verbose).then(encoding => { + resolveTerminalEncoding(verbose).then(async encoding => { + const iconv = await import('iconv-lite'); const converterStream = iconv.decodeStream(encoding); process.stdin.pipe(converterStream).pipe(stdinFileStream); }); @@ -360,10 +360,6 @@ export async function main(argv: string[]): Promise { options['stdio'] = 'ignore'; } - if (isLinux) { - addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox - } - const child = spawn(process.execPath, argv.slice(2), options); if (args.wait && waitMarkerFilePath) { diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts deleted file mode 100644 index 754dd46d1d..0000000000 --- a/src/vs/code/node/windowsFinder.ts +++ /dev/null @@ -1,131 +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 platform from 'vs/base/common/platform'; -import * as extpath from 'vs/base/common/extpath'; -import { OpenContext } from 'vs/platform/windows/common/windows'; -import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { URI } from 'vs/base/common/uri'; -import { isEqual, isEqualOrParent } from 'vs/base/common/resources'; - -export interface ISimpleWindow { - openedWorkspace?: IWorkspaceIdentifier; - openedFolderUri?: URI; - - extensionDevelopmentPath?: string[]; - lastFocusTime: number; -} - -export interface IBestWindowOrFolderOptions { - windows: W[]; - newWindow: boolean; - context: OpenContext; - fileUri?: URI; - userHome?: string; - codeSettingsFolder?: string; - localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null; -} - -export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { - if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) { - const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver); - if (windowOnFilePath) { - return windowOnFilePath; - } - } - return !newWindow ? getLastActiveWindow(windows) : undefined; -} - -function findWindowOnFilePath(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { - - // First check for windows with workspaces that have a parent folder of the provided path opened - for (const window of windows) { - const workspace = window.openedWorkspace; - if (workspace) { - const resolvedWorkspace = localWorkspaceResolver(workspace); - if (resolvedWorkspace) { - // workspace could be resolved: It's in the local file system - if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) { - return window; - } - } else { - // use the config path instead - if (isEqualOrParent(fileUri, workspace.configPath)) { - return window; - } - } - } - } - - // Then go with single folder windows that are parent of the provided file path - const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri)); - if (singleFolderWindowsOnFilePath.length) { - return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0]; - } - - return null; -} - -export function getLastActiveWindow(windows: W[]): W | undefined { - const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); - - return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0]; -} - -export function findWindowOnWorkspace(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null { - if (isSingleFolderWorkspaceIdentifier(workspace)) { - for (const window of windows) { - // match on folder - if (isSingleFolderWorkspaceIdentifier(workspace)) { - if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) { - return window; - } - } - } - } else if (isWorkspaceIdentifier(workspace)) { - for (const window of windows) { - // match on workspace - if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) { - return window; - } - } - } - return null; -} - -export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { - - const matches = (uriString: string): boolean => { - return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); - }; - - for (const window of windows) { - // match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough - const currPaths = window.extensionDevelopmentPath; - if (currPaths && currPaths.some(p => matches(p))) { - return window; - } - } - - return null; -} - -export function findWindowOnWorkspaceOrFolderUri(windows: W[], uri: URI | undefined): W | null { - if (!uri) { - return null; - } - for (const window of windows) { - // check for workspace config path - if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) { - return window; - } - - // check for folder path - if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) { - return window; - } - } - return null; -} diff --git a/src/vs/code/test/node/fixtures/no_vscode_folder/file.txt b/src/vs/code/test/node/fixtures/no_vscode_folder/file.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_folder/_vscode/settings.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/file.txt b/src/vs/code/test/node/fixtures/vscode_folder/file.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_folder/nested_vscode_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_folder/nested_vscode_folder/_vscode/settings.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json b/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/src/vs/code/test/node/fixtures/vscode_home_folder/_vscode/settings.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/src/vs/code/test/node/fixtures/vscode_home_folder/file.txt b/src/vs/code/test/node/fixtures/vscode_home_folder/file.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index a2b2b5d83b..24dbe9e974 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -310,13 +310,13 @@ export class Configuration extends CommonEditorConfiguration { constructor( isSimpleWidget: boolean, - options: IEditorOptions, + options: IEditorConstructionOptions, referenceDomElement: HTMLElement | null = null, private readonly accessibilityService: IAccessibilityService ) { super(isSimpleWidget, options); - this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, () => this._onReferenceDomElementSizeChanged())); + this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._onReferenceDomElementSizeChanged())); this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged())); diff --git a/src/vs/editor/browser/config/elementSizeObserver.ts b/src/vs/editor/browser/config/elementSizeObserver.ts index a372dc700e..f26929fe21 100644 --- a/src/vs/editor/browser/config/elementSizeObserver.ts +++ b/src/vs/editor/browser/config/elementSizeObserver.ts @@ -14,14 +14,14 @@ export class ElementSizeObserver extends Disposable { private width: number; private height: number; - constructor(referenceDomElement: HTMLElement | null, changeCallback: () => void) { + constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) { super(); this.referenceDomElement = referenceDomElement; this.changeCallback = changeCallback; this.measureReferenceDomElementToken = -1; this.width = -1; this.height = -1; - this.measureReferenceDomElement(false); + this.measureReferenceDomElement(false, dimension); } public dispose(): void { @@ -75,4 +75,4 @@ export class ElementSizeObserver extends Disposable { } } -} \ No newline at end of file +} diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index b4f9b34258..7b87db0424 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -190,7 +190,7 @@ class TouchHandler extends MouseHandler { constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { super(context, viewController, viewHelper); - Gesture.addTarget(this.viewHelper.linesContentDomNode); + this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode)); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 49bf05b4f9..6d273165ee 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -152,6 +152,10 @@ export class TextAreaHandler extends ViewPart { this.textArea.setAttribute('aria-haspopup', 'false'); this.textArea.setAttribute('aria-autocomplete', 'both'); + if (platform.isWeb && options.get(EditorOption.readOnly)) { + this.textArea.setAttribute('readonly', 'true'); + } + this.textAreaCover = createFastDomNode(document.createElement('div')); this.textAreaCover.setPosition('absolute'); @@ -395,6 +399,14 @@ export class TextAreaHandler extends ViewPart { this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting); this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); + if (platform.isWeb && e.hasChanged(EditorOption.readOnly)) { + if (options.get(EditorOption.readOnly)) { + this.textArea.setAttribute('readonly', 'true'); + } else { + this.textArea.removeAttribute('readonly'); + } + } + if (e.hasChanged(EditorOption.accessibilitySupport)) { this._textAreaInput.writeScreenReaderContent('strategy changed'); } diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 5dc1565d40..309b285e24 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -29,6 +29,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; import { Selection } from 'vs/editor/common/core/selection'; import { Color } from 'vs/base/common/color'; +import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch'; function getMinimapLineHeight(renderMinimap: RenderMinimap): number { if (renderMinimap === RenderMinimap.Large) { @@ -208,6 +209,10 @@ class MinimapLayout { return Math.round(desiredSliderPosition / this._computedSliderRatio); } + public getDesiredScrollTopFromTouchLocation(pageY: number): number { + return Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio); + } + public static create( options: MinimapOptions, viewportStartLineNumber: number, @@ -451,12 +456,17 @@ export class Minimap extends ViewPart { private readonly _mouseDownListener: IDisposable; private readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor; private readonly _sliderMouseDownListener: IDisposable; + private readonly _gestureDisposable: IDisposable; + private readonly _sliderTouchStartListener: IDisposable; + private readonly _sliderTouchMoveListener: IDisposable; + private readonly _sliderTouchEndListener: IDisposable; private _options: MinimapOptions; private _lastRenderData: RenderData | null; private _selections: Selection[] = []; private _selectionColor: Color | undefined; private _renderDecorations: boolean = false; + private _gestureInProgress: boolean = false; private _buffers: MinimapBuffers | null; constructor(context: ViewContext) { @@ -566,12 +576,50 @@ export class Minimap extends ViewPart { ); } }); + + this._gestureDisposable = Gesture.addTarget(this._domNode.domNode); + this._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (this._lastRenderData) { + this._slider.toggleClassName('active', true); + this._gestureInProgress = true; + this.scrollDueToTouchEvent(e); + } + }); + + this._sliderTouchMoveListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (this._lastRenderData && this._gestureInProgress) { + this.scrollDueToTouchEvent(e); + } + }); + + this._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => { + e.preventDefault(); + e.stopPropagation(); + this._gestureInProgress = false; + this._slider.toggleClassName('active', false); + }); + } + + private scrollDueToTouchEvent(touch: GestureEvent) { + const startY = this._domNode.domNode.getBoundingClientRect().top; + const scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY); + this._context.viewLayout.setScrollPositionNow({ + scrollTop: scrollTop + }); } public dispose(): void { this._mouseDownListener.dispose(); this._sliderMouseMoveMonitor.dispose(); this._sliderMouseDownListener.dispose(); + this._gestureDisposable.dispose(); + this._sliderTouchStartListener.dispose(); + this._sliderTouchMoveListener.dispose(); + this._sliderTouchEndListener.dispose(); super.dispose(); } diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 9875ed2f6b..7b0227d5ab 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; -import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -236,7 +236,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE constructor( domElement: HTMLElement, - options: IEditorOptions, + options: IEditorConstructionOptions, codeEditorWidgetOptions: ICodeEditorWidgetOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -329,7 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._codeEditorService.addCodeEditor(this); } - protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { + protected _createConfiguration(options: IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration { return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService); } diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 139141fa31..1d2d536fa1 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -12,6 +12,7 @@ import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isObject } from 'vs/base/common/types'; import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; +import { IDimension } from 'vs/editor/common/editorCommon'; //#region typed options @@ -516,6 +517,13 @@ export interface IEditorOptions { showUnused?: boolean; } +export interface IEditorConstructionOptions extends IEditorOptions { + /** + * The initial editor dimension (to avoid measuring the container). + */ + dimension?: IDimension; +} + /** * Configuration options for the diff editor. */ diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 3305765401..1cec833095 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -280,6 +280,8 @@ export interface IEditor { /** * Instructs the editor to remeasure its container. This method should * be called when the container of the editor gets resized. + * + * If a dimension is passed in, the passed in value will be used. */ layout(dimension?: IDimension): void; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 914f7f0103..cbab3921d5 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -922,7 +922,7 @@ export interface DocumentSymbol { /** * The document symbol provider interface defines the contract between extensions and - * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature. + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. */ export interface DocumentSymbolProvider { diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index 3cc0150c1d..372de6f425 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -14,7 +14,7 @@ import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel'; +import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel'; import { FoldingDecorationProvider } from './foldingDecorations'; import { FoldingRegions, FoldingRegion } from './foldingRanges'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -656,6 +656,30 @@ class FoldAction extends FoldingAction { } } + +class ToggleFoldAction extends FoldingAction { + + constructor() { + super({ + id: 'editor.toggleFold', + label: nls.localize('toggleFoldAction.label', "Toggle Fold"), + alias: 'Toggle Fold', + precondition: CONTEXT_FOLDING_ENABLED, + kbOpts: { + kbExpr: EditorContextKeys.editorTextFocus, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K), + weight: KeybindingWeight.EditorContrib + } + }); + } + + invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void { + let selectedLines = this.getSelectedLines(editor); + toggleCollapseState(foldingModel, 1, selectedLines); + } +} + + class FoldRecursivelyAction extends FoldingAction { constructor() { @@ -842,6 +866,7 @@ registerEditorAction(UnfoldAllAction); registerEditorAction(FoldAllBlockCommentsAction); registerEditorAction(FoldAllRegionsAction); registerEditorAction(UnfoldAllRegionsAction); +registerEditorAction(ToggleFoldAction); for (let i = 1; i <= 7; i++) { registerInstantiatedEditorAction( diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 1a41e37564..0e8d76a170 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -242,6 +242,26 @@ export class FoldingModel { } +/** + * Collapse or expand the regions at the given locations + * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels. + * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model. + */ +export function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) { + let toToggle: FoldingRegion[] = []; + for (let lineNumber of lineNumbers) { + let region = foldingModel.getRegionAtLine(lineNumber); + if (region) { + const doCollapse = !region.isCollapsed; + toToggle.push(region); + if (levels > 1) { + let regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels); + toToggle.push(...regionsInside); + } + } + } + foldingModel.toggleCollapseState(toToggle); +} /** diff --git a/src/vs/editor/contrib/hover/hover.css b/src/vs/editor/contrib/hover/hover.css index 5b63d89b20..b1a4f32e97 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -37,7 +37,7 @@ margin: 8px 0; } -.monaco-editor-hover p > code { +.monaco-editor-hover code { font-family: var(--monaco-monospace-font); } diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 3ad81340d5..8116d49e5d 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -53,7 +53,7 @@ padding-left: 20px; } -.monaco-editor .suggest-widget > .details p > code { +.monaco-editor .suggest-widget > .details p code { font-family: var(--monaco-monospace-font); } diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index 172f6d11ba..066393ff22 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -21,7 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode'; -import { IEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor'; +import { IStandaloneEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -164,7 +164,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget { if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) { alert(AccessibilityHelpNLS.openingDocs); - let url = (this._editor.getRawOptions()).accessibilityHelpUrl; + let url = (this._editor.getRawOptions()).accessibilityHelpUrl; if (typeof url === 'undefined') { url = 'https://go.microsoft.com/fwlink/?linkid=852450'; } diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 5bb1b6d3df..0fcc1c12d1 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -10,7 +10,7 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { InternalEditorAction } from 'vs/editor/common/editorAction'; import { IModelChangedEvent } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; @@ -79,7 +79,7 @@ export interface IActionDescriptor { /** * The options to create an editor. */ -export interface IEditorConstructionOptions extends IEditorOptions { +export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions { /** * The initial model associated with this code editor. */ @@ -158,7 +158,7 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon constructor( domElement: HTMLElement, - options: IEditorConstructionOptions, + options: IStandaloneEditorConstructionOptions, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @ICommandService commandService: ICommandService, @@ -287,7 +287,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon constructor( domElement: HTMLElement, - options: IEditorConstructionOptions | undefined, + options: IStandaloneEditorConstructionOptions | undefined, toDispose: IDisposable, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 66092ac141..72d640f10f 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -24,7 +24,7 @@ import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebW import * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums'; import { Colorizer, IColorizerElementOptions, IColorizerOptions } from 'vs/editor/standalone/browser/colorizer'; import { SimpleEditorModelResolverService } from 'vs/editor/standalone/browser/simpleServices'; -import { IDiffEditorConstructionOptions, IEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor'; +import { IDiffEditorConstructionOptions, IStandaloneEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor'; import { DynamicStandaloneServices, IEditorOverrideServices, StaticServices } from 'vs/editor/standalone/browser/standaloneServices'; import { IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -68,7 +68,7 @@ function withAllStandaloneServices(domElement: H * `domElement` should be empty (not contain other dom nodes). * The editor will read the size of `domElement`. */ -export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor { +export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor { return withAllStandaloneServices(domElement, override || {}, (services) => { return new StandaloneEditor( domElement, diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index fba696bf76..1c7fb6bad4 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -29,7 +29,7 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.ICodeEditor { //#region testing overrides - protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration { + protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): editorCommon.IConfiguration { return new TestConfiguration(options); } protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 32714a6767..051c6543fd 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -813,7 +813,7 @@ declare namespace monaco.editor { * `domElement` should be empty (not contain other dom nodes). * The editor will read the size of `domElement`. */ - export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor; + export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor; /** * Emitted when an editor is created. @@ -1051,7 +1051,7 @@ declare namespace monaco.editor { /** * The options to create an editor. */ - export interface IEditorConstructionOptions extends IEditorOptions { + export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions { /** * The initial model associated with this code editor. */ @@ -2061,6 +2061,8 @@ declare namespace monaco.editor { /** * Instructs the editor to remeasure its container. This method should * be called when the container of the editor gets resized. + * + * If a dimension is passed in, the passed in value will be used. */ layout(dimension?: IDimension): void; /** @@ -2918,6 +2920,13 @@ declare namespace monaco.editor { showUnused?: boolean; } + export interface IEditorConstructionOptions extends IEditorOptions { + /** + * The initial editor dimension (to avoid measuring the container). + */ + dimension?: IDimension; + } + /** * Configuration options for the diff editor. */ @@ -5131,7 +5140,7 @@ declare namespace monaco.languages { /** * The document symbol provider interface defines the contract between extensions and - * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature. + * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature. */ export interface DocumentSymbolProvider { displayName?: string; diff --git a/src/vs/platform/auth/common/authTokenService.ts b/src/vs/platform/auth/common/authTokenService.ts index 1cc3cf398f..23c2c3565f 100644 --- a/src/vs/platform/auth/common/authTokenService.ts +++ b/src/vs/platform/auth/common/authTokenService.ts @@ -8,6 +8,7 @@ import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { Disposable } from 'vs/base/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const SERVICE_NAME = 'VS Code'; const ACCOUNT = 'MyAccount'; @@ -23,9 +24,10 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { constructor( @ICredentialsService private readonly credentialsService: ICredentialsService, @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, ) { super(); - if (productService.settingsSyncStoreUrl) { + if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { this._status = AuthTokenStatus.Inactive; this.getToken().then(token => { if (token) { diff --git a/src/vs/platform/dialogs/electron-main/dialogs.ts b/src/vs/platform/dialogs/electron-main/dialogs.ts new file mode 100644 index 0000000000..9804e7067b --- /dev/null +++ b/src/vs/platform/dialogs/electron-main/dialogs.ts @@ -0,0 +1,211 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, dialog, FileFilter, BrowserWindow } from 'electron'; +import { Queue } from 'vs/base/common/async'; +import { IStateService } from 'vs/platform/state/node/state'; +import { isMacintosh } from 'vs/base/common/platform'; +import { dirname } from 'vs/base/common/path'; +import { normalizeNFC } from 'vs/base/common/normalization'; +import { exists } from 'vs/base/node/pfs'; +import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { localize } from 'vs/nls'; +import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; + +export const IDialogMainService = createDecorator('dialogMainService'); + +export interface IDialogMainService { + + _serviceBrand: undefined; + + pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise; + + showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise; + showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise; + showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise; +} + +interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions { + pickFolders?: boolean; + pickFiles?: boolean; + + title: string; + buttonLabel?: string; + filters?: FileFilter[]; +} + +export class DialogMainService implements IDialogMainService { + + _serviceBrand: undefined; + + private static readonly workingDirPickerStorageKey = 'pickerWorkingDir'; + + private readonly mapWindowToDialogQueue: Map>; + private readonly noWindowDialogQueue: Queue; + + constructor( + @IStateService private readonly stateService: IStateService + ) { + this.mapWindowToDialogQueue = new Map>(); + this.noWindowDialogQueue = new Queue(); + } + + pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFolders: true, pickFiles: true, title: localize('open', "Open") }, window); + } + + pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFolders: true, title: localize('openFolder', "Open Folder") }, window); + } + + pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + return this.doPick({ ...options, pickFiles: true, title: localize('openFile', "Open File") }, window); + } + + pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise { + const title = localize('openWorkspaceTitle', "Open Workspace"); + const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open")); + const filters = WORKSPACE_FILTER; + + return this.doPick({ ...options, pickFiles: true, title, filters, buttonLabel }, window); + } + + private async doPick(options: IInternalNativeOpenDialogOptions, window?: BrowserWindow): Promise { + + // Ensure dialog options + const dialogOptions: OpenDialogOptions = { + title: options.title, + buttonLabel: options.buttonLabel, + filters: options.filters + }; + + // Ensure defaultPath + dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem(DialogMainService.workingDirPickerStorageKey); + + + // Ensure properties + if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') { + dialogOptions.properties = undefined; // let it override based on the booleans + + if (options.pickFiles && options.pickFolders) { + dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory']; + } + } + + if (!dialogOptions.properties) { + dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory']; + } + + if (isMacintosh) { + dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files + } + + // Show Dialog + const windowToUse = window || BrowserWindow.getFocusedWindow(); + + const result = await this.showOpenDialog(dialogOptions, withNullAsUndefined(windowToUse)); + if (result && result.filePaths && result.filePaths.length > 0) { + + // Remember path in storage for next time + this.stateService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0])); + + return result.filePaths; + } + + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + private getDialogQueue(window?: BrowserWindow): Queue { + if (!window) { + return this.noWindowDialogQueue; + } + + let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id); + if (!windowDialogQueue) { + windowDialogQueue = new Queue(); + this.mapWindowToDialogQueue.set(window.id, windowDialogQueue); + } + + return windowDialogQueue; + } + + showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise { + return this.getDialogQueue(window).queue(async () => { + return new Promise(resolve => { + if (window) { + return dialog.showMessageBox(window, options, (response, checkboxChecked) => resolve({ response, checkboxChecked })); + } + + return dialog.showMessageBox(options); + }); + }); + } + + showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise { + + function normalizePath(path: string | undefined): string | undefined { + if (path && isMacintosh) { + path = normalizeNFC(path); // normalize paths returned from the OS + } + + return path; + } + + return this.getDialogQueue(window).queue(async () => { + return new Promise(resolve => { + if (window) { + dialog.showSaveDialog(window, options, filePath => resolve({ filePath })); + } else { + dialog.showSaveDialog(options, filePath => resolve({ filePath })); + } + }).then(result => { + result.filePath = normalizePath(result.filePath); + + return result; + }); + }); + } + + showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise { + + function normalizePaths(paths: string[] | undefined): string[] | undefined { + if (paths && paths.length > 0 && isMacintosh) { + paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS + } + + return paths; + } + + return this.getDialogQueue(window).queue(async () => { + + // Ensure the path exists (if provided) + if (options.defaultPath) { + const pathExists = await exists(options.defaultPath); + if (!pathExists) { + options.defaultPath = undefined; + } + } + + // Show dialog + return new Promise(resolve => { + if (window) { + dialog.showOpenDialog(window, options, filePaths => resolve({ filePaths })); + } else { + dialog.showOpenDialog(options, filePaths => resolve({ filePaths })); + } + }).then(result => { + result.filePaths = normalizePaths(result.filePaths); + + return result; + }); + }); + } +} diff --git a/src/vs/platform/dialogs/node/dialogs.ts b/src/vs/platform/dialogs/node/dialogs.ts index 13a3ff5696..37389a681e 100644 --- a/src/vs/platform/dialogs/node/dialogs.ts +++ b/src/vs/platform/dialogs/node/dialogs.ts @@ -13,3 +13,16 @@ export interface INativeOpenDialogOptions { telemetryEventName?: string; telemetryExtraData?: ITelemetryData; } + +export interface MessageBoxReturnValue { + response: number; + checkboxChecked: boolean; +} + +export interface SaveDialogReturnValue { + filePath?: string; +} + +export interface OpenDialogReturnValue { + filePaths?: string[]; +} diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index 6db4f453e4..d01fcecdc7 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -5,16 +5,17 @@ import { Event } from 'vs/base/common/event'; import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; -import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron'; -import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window'; +import { MessageBoxOptions, shell, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IOpenedWindow, OpenContext, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; -import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; +import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs'; import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { AddFirstParameterToFunctions } from 'vs/base/common/types'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; export class ElectronMainService implements AddFirstParameterToFunctions /* only methods, not events */, number /* window ID */> { @@ -22,6 +23,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions { - const activeWindow = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); + const activeWindow = BrowserWindow.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); if (activeWindow) { return activeWindow.id; } @@ -69,11 +71,17 @@ export class ElectronMainService implements AddFirstParameterToFunctions { - this.windowsMainService.openEmptyWindow(OpenContext.API, options); + openWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise; + openWindow(windowId: number, toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise; + openWindow(windowId: number, arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: INativeOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(windowId, arg1, arg2); + } + + return this.doOpenEmptyWindow(windowId, arg1); } - async openInWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenInWindowOptions = Object.create(null)): Promise { + private async doOpenWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenWindowOptions = Object.create(null)): Promise { if (toOpen.length > 0) { this.windowsMainService.open({ context: OpenContext.API, @@ -91,6 +99,10 @@ export class ElectronMainService implements AddFirstParameterToFunctions { + this.windowsMainService.openEmptyWindow(OpenContext.API, options); + } + async toggleFullScreen(windowId: number): Promise { const window = this.windowsMainService.getWindowById(windowId); if (window) { @@ -164,15 +176,24 @@ export class ElectronMainService implements AddFirstParameterToFunctions { - return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId)); + return this.dialogMainService.showMessageBox(options, this.toBrowserWindow(windowId)); } async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise { - return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId)); + return this.dialogMainService.showSaveDialog(options, this.toBrowserWindow(windowId)); } async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise { - return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId)); + return this.dialogMainService.showOpenDialog(options, this.toBrowserWindow(windowId)); + } + + private toBrowserWindow(windowId: number): BrowserWindow | undefined { + const window = this.windowsMainService.getWindowById(windowId); + if (window) { + return window.win; + } + + return undefined; } async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { @@ -214,7 +235,9 @@ export class ElectronMainService implements AddFirstParameterToFunctions { - return this.windowsMainService.openExternal(url); + shell.openExternal(url); + + return true; } async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise { @@ -229,7 +252,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions { - this.windowsMainService.openNewTabbedWindow(OpenContext.API); + this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true }); } async showPreviousWindowTab(): Promise { @@ -267,7 +290,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions { + async closeWorkspace(windowId: number): Promise { const window = this.windowsMainService.getWindowById(windowId); if (window) { return this.windowsMainService.closeWorkspace(window); diff --git a/src/vs/platform/electron/node/electron.ts b/src/vs/platform/electron/node/electron.ts index c17b6b643b..8a964db380 100644 --- a/src/vs/platform/electron/node/electron.ts +++ b/src/vs/platform/electron/node/electron.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron'; +import { MessageBoxOptions, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions } from 'electron'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWindowOpenable, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows'; -import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; +import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { ParsedArgs } from 'vscode-minimist'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; export const IElectronService = createDecorator('electronService'); @@ -33,8 +33,8 @@ export interface IElectronService { getWindowCount(): Promise; getActiveWindowId(): Promise; - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise; - openInWindow(toOpen: IWindowOpenable[], options?: INativeOpenInWindowOptions): Promise; + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise; toggleFullScreen(): Promise; @@ -76,7 +76,7 @@ export interface IElectronService { // Lifecycle relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise; reload(): Promise; - closeWorkpsace(): Promise; + closeWorkspace(): Promise; closeWindow(): Promise; quit(): Promise; diff --git a/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts b/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts index 4f3e12bdd8..db654a3b12 100644 --- a/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts +++ b/src/vs/platform/ipc/electron-main/sharedProcessMainService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; export const ISharedProcessMainService = createDecorator('sharedProcessMainService'); @@ -15,6 +14,12 @@ export interface ISharedProcessMainService { whenSharedProcessReady(): Promise; toggleSharedProcessWindow(): Promise; } + +export interface ISharedProcess { + whenReady(): Promise; + toggle(): void; +} + export class SharedProcessMainService implements ISharedProcessMainService { _serviceBrand: undefined; diff --git a/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts index 4747524b53..1dcb6e92d0 100644 --- a/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -7,15 +7,16 @@ import { localize } from 'vs/nls'; import * as objects from 'vs/base/common/objects'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue'; -import { BrowserWindow, ipcMain, screen, dialog, IpcMainEvent, Display } from 'electron'; +import { BrowserWindow, ipcMain, screen, Event as IpcMainEvent, Display, shell } from 'electron'; import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { PerformanceInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowState, IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { IWindowState } from 'vs/platform/windows/electron-main/windows'; import { listProcesses } from 'vs/base/node/ps'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; const DEFAULT_BACKGROUND_COLOR = '#1E1E1E'; @@ -33,7 +34,7 @@ export class IssueMainService implements IIssueService { @ILaunchMainService private readonly launchMainService: ILaunchMainService, @ILogService private readonly logService: ILogService, @IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService, - @IWindowsMainService private readonly windowsMainService: IWindowsMainService + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { this.registerListeners(); } @@ -89,7 +90,7 @@ export class IssueMainService implements IIssueService { }; if (this._issueWindow) { - dialog.showMessageBox(this._issueWindow, messageOptions) + this.dialogMainService.showMessageBox(messageOptions, this._issueWindow) .then(result => { event.sender.send('vscode:issueReporterClipboardResponse', result.response === 0); }); @@ -113,7 +114,7 @@ export class IssueMainService implements IIssueService { }; if (this._issueWindow) { - dialog.showMessageBox(this._issueWindow, messageOptions) + this.dialogMainService.showMessageBox(messageOptions, this._issueWindow) .then(result => { if (result.response === 0) { if (this._issueWindow) { @@ -146,7 +147,7 @@ export class IssueMainService implements IIssueService { }); ipcMain.on('vscode:openExternal', (_: unknown, arg: string) => { - this.windowsMainService.openExternal(arg); + shell.openExternal(arg); }); ipcMain.on('vscode:closeIssueReporter', (event: IpcMainEvent) => { diff --git a/src/vs/platform/launch/electron-main/launchMainService.ts b/src/vs/platform/launch/electron-main/launchMainService.ts index e8e7e6b2ca..740dafdeff 100644 --- a/src/vs/platform/launch/electron-main/launchMainService.ts +++ b/src/vs/platform/launch/electron-main/launchMainService.ts @@ -141,6 +141,7 @@ export class LaunchMainService implements ILaunchMainService { } } + // Open new Window if (openNewWindow) { usedWindows = this.windowsMainService.open({ context, @@ -150,8 +151,18 @@ export class LaunchMainService implements ILaunchMainService { forceEmpty: true, waitMarkerFileURI }); - } else { - usedWindows = [this.windowsMainService.focusLastActive(args, context)]; + } + + // Focus existing window or open if none opened + else { + const lastActive = this.windowsMainService.getLastActiveWindow(); + if (lastActive) { + lastActive.focus(); + + usedWindows = [lastActive]; + } else { + usedWindows = this.windowsMainService.open({ context, cli: args, forceEmpty: true }); + } } } @@ -216,7 +227,7 @@ export class LaunchMainService implements ILaunchMainService { mainPID: process.pid, mainArguments: process.argv.slice(1), windows, - screenReader: !!app.accessibilitySupportEnabled, + screenReader: !!app.isAccessibilitySupportEnabled(), gpuFeatureStatus: app.getGPUFeatureStatus() }); } diff --git a/src/vs/platform/log/common/bufferLog.ts b/src/vs/platform/log/common/bufferLog.ts index 204e831d70..3d74dd0741 100644 --- a/src/vs/platform/log/common/bufferLog.ts +++ b/src/vs/platform/log/common/bufferLog.ts @@ -87,4 +87,10 @@ export class BufferLogService extends AbstractLogService implements ILogService this._logger.dispose(); } } + + flush(): void { + if (this._logger) { + this._logger.flush(); + } + } } diff --git a/src/vs/platform/log/common/fileLogService.ts b/src/vs/platform/log/common/fileLogService.ts index 91888bd3d9..d7376e06f6 100644 --- a/src/vs/platform/log/common/fileLogService.ts +++ b/src/vs/platform/log/common/fileLogService.ts @@ -78,8 +78,7 @@ export class FileLogService extends AbstractLogService implements ILogService { } } - flush(): Promise { - return this.queue.queue(() => Promise.resolve()); + flush(): void { } log(level: LogLevel, args: any[]): void { diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index ea9c15b518..0a70019bc3 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -41,6 +41,11 @@ export interface ILogger extends IDisposable { warn(message: string, ...args: any[]): void; error(message: string | Error, ...args: any[]): void; critical(message: string | Error, ...args: any[]): void; + + /** + * An operation to flush the contents. Can be synchronous. + */ + flush(): void; } export interface ILogService extends ILogger { @@ -69,6 +74,7 @@ export abstract class AbstractLogService extends Disposable { getLevel(): LogLevel { return this.level; } + } export class ConsoleLogMainService extends AbstractLogService implements ILogService { @@ -145,6 +151,11 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer dispose(): void { // noop } + + flush(): void { + // noop + } + } export class ConsoleLogService extends AbstractLogService implements ILogService { @@ -192,7 +203,13 @@ export class ConsoleLogService extends AbstractLogService implements ILogService } } - dispose(): void { } + dispose(): void { + // noop + } + + flush(): void { + // noop + } } export class ConsoleLogInMainService extends AbstractLogService implements ILogService { @@ -240,7 +257,13 @@ export class ConsoleLogInMainService extends AbstractLogService implements ILogS } } - dispose(): void { } + dispose(): void { + // noop + } + + flush(): void { + // noop + } } export class MultiplexLogService extends AbstractLogService implements ILogService { @@ -296,6 +319,12 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi } } + flush(): void { + for (const logService of this.logServices) { + logService.flush(); + } + } + dispose(): void { for (const logService of this.logServices) { logService.dispose(); @@ -346,6 +375,10 @@ export class DelegatedLogService extends Disposable implements ILogService { critical(message: string | Error, ...args: any[]): void { this.logService.critical(message, ...args); } + + flush(): void { + this.logService.flush(); + } } export class NullLogService implements ILogService { @@ -360,6 +393,7 @@ export class NullLogService implements ILogService { error(message: string | Error, ...args: any[]): void { } critical(message: string | Error, ...args: any[]): void { } dispose(): void { } + flush(): void { } } export function getLogLevel(environmentService: IEnvironmentService): LogLevel { diff --git a/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts index 778ac4294b..5fd73bfcc5 100644 --- a/src/vs/platform/log/node/loggerService.ts +++ b/src/vs/platform/log/node/loggerService.ts @@ -32,7 +32,7 @@ export class LoggerService extends Disposable implements ILoggerService { if (resource.scheme === Schemas.file) { const baseName = basename(resource); const ext = extname(resource); - logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).path, this.logService.getLevel()); + logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel()); } else { logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel()); } diff --git a/src/vs/platform/log/node/spdlogService.ts b/src/vs/platform/log/node/spdlogService.ts index 4b957311e1..42158af6d7 100644 --- a/src/vs/platform/log/node/spdlogService.ts +++ b/src/vs/platform/log/node/spdlogService.ts @@ -30,7 +30,7 @@ interface ILog { message: string; } -function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sync: boolean): void { +function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void { switch (level) { case LogLevel.Trace: logger.trace(message); break; case LogLevel.Debug: logger.debug(message); break; @@ -40,9 +40,6 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sy case LogLevel.Critical: logger.critical(message); break; default: throw new Error('Invalid log level'); } - if (sync) { - logger.flush(); - } } export class SpdLogService extends AbstractLogService implements ILogService { @@ -53,7 +50,7 @@ export class SpdLogService extends AbstractLogService implements ILogService { private _loggerCreationPromise: Promise | undefined = undefined; private _logger: spdlog.RotatingLogger | undefined; - constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel, private readonly sync: boolean = false) { + constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel) { super(); this.setLevel(level); this._createSpdLogLogger(); @@ -72,7 +69,7 @@ export class SpdLogService extends AbstractLogService implements ILogService { this._logger = logger; this._logger.setLevel(this.getLevel()); for (const { level, message } of this.buffer) { - log(this._logger, level, message, this.sync); + log(this._logger, level, message); } this.buffer = []; } @@ -83,7 +80,7 @@ export class SpdLogService extends AbstractLogService implements ILogService { private _log(level: LogLevel, message: string): void { if (this._logger) { - log(this._logger, level, message, this.sync); + log(this._logger, level, message); } else if (this.getLevel() <= level) { this.buffer.push({ level, message }); } @@ -132,6 +129,14 @@ export class SpdLogService extends AbstractLogService implements ILogService { } } + flush(): void { + if (this._logger) { + this._logger.flush(); + } else if (this._loggerCreationPromise) { + this._loggerCreationPromise.then(() => this.flush()); + } + } + dispose(): void { if (this._logger) { this.disposeLogger(); diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 676d8304de..17c24f7be1 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { isMacintosh, language } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, KeyboardEvent } from 'electron'; +import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, Event as KeyboardEvent } from 'electron'; import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -368,13 +368,13 @@ export class Menubar { const servicesMenu = new Menu(); const services = new MenuItem({ label: nls.localize('mServices', "Services"), role: 'services', submenu: servicesMenu }); const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", product.nameLong), role: 'hide', accelerator: 'Command+H' }); - const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideOthers', accelerator: 'Command+Alt+H' }); + const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideothers', accelerator: 'Command+Alt+H' }); const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' }); const quit = new MenuItem(this.likeAction('workbench.action.quit', { label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => { if ( - this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open - !!this.windowsMainService.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191) + this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open + !!BrowserWindow.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191) this.windowsMainService.getLastActiveWindow()!.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/Microsoft/vscode/issues/63000) ) { this.windowsMainService.quit(); @@ -557,7 +557,7 @@ export class Menubar { label: this.mnemonicLabel(nls.localize('miCheckForUpdates', "Check for &&Updates...")), click: () => setTimeout(() => { this.reportMenuActionTelemetry('CheckForUpdate'); - const focusedWindow = this.windowsMainService.getFocusedWindow(); + const focusedWindow = BrowserWindow.getFocusedWindow(); const context = focusedWindow ? { windowId: focusedWindow.id } : null; this.updateService.checkForUpdates(context); }, 0) @@ -697,15 +697,16 @@ export class Menubar { private makeContextAwareClickHandler(click: () => void, contextSpecificHandlers: IMenuItemClickHandler): () => void { return () => { + // No Active Window - const activeWindow = this.windowsMainService.getFocusedWindow(); + const activeWindow = BrowserWindow.getFocusedWindow(); if (!activeWindow) { return contextSpecificHandlers.inNoWindow(); } // DevTools focused - if (activeWindow.win.webContents.isDevToolsFocused()) { - return contextSpecificHandlers.inDevTools(activeWindow.win.webContents.devToolsWebContents); + if (activeWindow.webContents.isDevToolsFocused()) { + return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents); } // Finally execute command in Window @@ -719,14 +720,15 @@ export class Menubar { // https://github.com/Microsoft/vscode/issues/11928 // Still allow to run when the last active window is minimized though for // https://github.com/Microsoft/vscode/issues/63000 - let activeWindow = this.windowsMainService.getFocusedWindow(); - if (!activeWindow) { + let activeBrowserWindow = BrowserWindow.getFocusedWindow(); + if (!activeBrowserWindow) { const lastActiveWindow = this.windowsMainService.getLastActiveWindow(); if (lastActiveWindow && lastActiveWindow.isMinimized()) { - activeWindow = lastActiveWindow; + activeBrowserWindow = lastActiveWindow.win; } } + const activeWindow = activeBrowserWindow ? this.windowsMainService.getWindowById(activeBrowserWindow.id) : undefined; if (activeWindow) { this.logService.trace('menubar#runActionInRenderer', invocation); diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index b1ed3932e3..919b2c46a1 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -27,7 +27,7 @@ export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address: if (uri.scheme !== 'http' && uri.scheme !== 'https') { return undefined; } - const localhostMatch = /^(localhost|127\.0\.0\.1):(\d+)$/.exec(uri.authority); + const localhostMatch = /^(localhost|127\.0\.0\.1|0\.0\.0\.0):(\d+)$/.exec(uri.authority); if (!localhostMatch) { return undefined; } diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts index 64b63f2e0b..3b0ccdf0f3 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -70,6 +70,7 @@ class TestableLogService extends AbstractLogService implements ILogService { } dispose(): void { } + flush(): void { } } suite('AIAdapter', () => { @@ -198,4 +199,4 @@ suite('AIAdapter', () => { } }])); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 6911680df5..cf793d87cd 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -63,6 +63,12 @@ export function registerConfiguration(): IDisposable { $ref: ignoredSettingsSchemaId, additionalProperties: true, uniqueItems: true + }, + 'configurationSync.enableAuth': { + 'type': 'boolean', + description: localize('configurationSync.enableAuth', "Enables authentication and requires VS Code restart when changed"), + 'default': false, + 'scope': ConfigurationScope.APPLICATION } } }); diff --git a/src/vs/platform/userDataSync/common/userDataSyncLog.ts b/src/vs/platform/userDataSync/common/userDataSyncLog.ts index 6c4f490fa0..43ebeba16a 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncLog.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncLog.ts @@ -44,4 +44,8 @@ export class UserDataSyncLogService extends AbstractLogService implements IUserD this.logger.critical(message, ...args); } + flush(): void { + this.logger.flush(); + } + } diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index df24380473..561ada7643 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -131,27 +131,32 @@ export class UserDataAutoSync extends Disposable { @IAuthTokenService private readonly authTokenService: IAuthTokenService, ) { super(); - this.updateEnablement(); - this.sync(true); - this._register(Event.any(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement())); - this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement())); + this.updateEnablement(false); + this._register(Event.any(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true))); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement(true))); // Sync immediately if there is a local change. this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false))); } - private updateEnablement(): void { + private updateEnablement(stopIfDisabled: boolean): void { const enabled = this.isSyncEnabled(); - if (this.enabled !== enabled) { - this.enabled = enabled; - if (this.enabled) { - this.userDataSyncLogService.info('Syncing configuration started'); - this.sync(true); - } else { + if (this.enabled === enabled) { + return; + } + + this.enabled = enabled; + if (this.enabled) { + this.userDataSyncLogService.info('Syncing configuration started'); + this.sync(true); + return; + } else { + if (stopIfDisabled) { this.userDataSyncService.stop(); this.userDataSyncLogService.info('Syncing configuration stopped.'); } } + } private async sync(loop: boolean): Promise { diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 4d1450ed5c..70f9079c08 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -19,15 +19,17 @@ export interface IOpenedWindow { filename?: string; } -export interface IOpenInWindowOptions { - forceNewWindow?: boolean; +export interface IBaseOpenWindowsOptions { forceReuseWindow?: boolean; +} + +export interface IOpenWindowOptions extends IBaseOpenWindowsOptions { + forceNewWindow?: boolean; noRecentEntry?: boolean; } -export interface IOpenEmptyWindowOptions { - reuse?: boolean; +export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions { remoteAuthority?: string; } diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 7447fa7759..9583c670c0 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -9,10 +9,10 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { URI } from 'vs/base/common/uri'; -import { MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue, Rectangle, BrowserWindow, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions } from 'electron'; +import { Rectangle, BrowserWindow } from 'electron'; export interface IWindowState { width?: number; @@ -86,38 +86,34 @@ export interface IWindowsCountChangedEvent { } export interface IWindowsMainService { + _serviceBrand: undefined; - // events readonly onWindowReady: Event; readonly onWindowsCountChanged: Event; readonly onWindowClose: Event; - // methods - reload(win: ICodeWindow, cli?: ParsedArgs): void; - enterWorkspace(win: ICodeWindow, path: URI): Promise; - closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; - openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void; + openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[]; + openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[]; + pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise; - showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise; - showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise; - showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise; - focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow; - getLastActiveWindow(): ICodeWindow | undefined; - waitForWindowCloseOrLoad(windowId: number): Promise; - openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[]; - openNewTabbedWindow(context: OpenContext): ICodeWindow[]; - openExternal(url: string): Promise; + sendToFocused(channel: string, ...args: any[]): void; sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void; - getFocusedWindow(): ICodeWindow | undefined; + + getLastActiveWindow(): ICodeWindow | undefined; + getWindowById(windowId: number): ICodeWindow | undefined; getWindows(): ICodeWindow[]; getWindowCount(): number; + + waitForWindowCloseOrLoad(windowId: number): Promise; + reload(win: ICodeWindow, cli?: ParsedArgs): void; + closeWorkspace(win: ICodeWindow): void; quit(): void; } @@ -139,8 +135,3 @@ export interface IOpenConfiguration { readonly initialStartup?: boolean; readonly noRecentEntry?: boolean; } - -export interface ISharedProcess { - whenReady(): Promise; - toggle(): void; -} diff --git a/src/vs/platform/windows/node/window.ts b/src/vs/platform/windows/node/window.ts index 6de95f4e4e..4765a18188 100644 --- a/src/vs/platform/windows/node/window.ts +++ b/src/vs/platform/windows/node/window.ts @@ -3,12 +3,136 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IOpenInWindowOptions } from 'vs/platform/windows/common/windows'; +import { OpenContext, IOpenWindowOptions } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; +import * as platform from 'vs/base/common/platform'; +import * as extpath from 'vs/base/common/extpath'; +import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { isEqual, isEqualOrParent } from 'vs/base/common/resources'; -export interface INativeOpenInWindowOptions extends IOpenInWindowOptions { +export interface INativeOpenWindowOptions extends IOpenWindowOptions { diffMode?: boolean; addMode?: boolean; gotoLineMode?: boolean; waitMarkerFileURI?: URI; } + +export interface IWindowContext { + openedWorkspace?: IWorkspaceIdentifier; + openedFolderUri?: URI; + + extensionDevelopmentPath?: string[]; + lastFocusTime: number; +} + +export interface IBestWindowOrFolderOptions { + windows: W[]; + newWindow: boolean; + context: OpenContext; + fileUri?: URI; + userHome?: string; + codeSettingsFolder?: string; + localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null; +} + +export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { + if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) { + const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver); + if (windowOnFilePath) { + return windowOnFilePath; + } + } + return !newWindow ? getLastActiveWindow(windows) : undefined; +} + +function findWindowOnFilePath(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { + + // First check for windows with workspaces that have a parent folder of the provided path opened + for (const window of windows) { + const workspace = window.openedWorkspace; + if (workspace) { + const resolvedWorkspace = localWorkspaceResolver(workspace); + if (resolvedWorkspace) { + // workspace could be resolved: It's in the local file system + if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) { + return window; + } + } else { + // use the config path instead + if (isEqualOrParent(fileUri, workspace.configPath)) { + return window; + } + } + } + } + + // Then go with single folder windows that are parent of the provided file path + const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri)); + if (singleFolderWindowsOnFilePath.length) { + return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0]; + } + + return null; +} + +export function getLastActiveWindow(windows: W[]): W | undefined { + const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime)); + + return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0]; +} + +export function findWindowOnWorkspace(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null { + if (isSingleFolderWorkspaceIdentifier(workspace)) { + for (const window of windows) { + // match on folder + if (isSingleFolderWorkspaceIdentifier(workspace)) { + if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) { + return window; + } + } + } + } else if (isWorkspaceIdentifier(workspace)) { + for (const window of windows) { + // match on workspace + if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) { + return window; + } + } + } + return null; +} + +export function findWindowOnExtensionDevelopmentPath(windows: W[], extensionDevelopmentPaths: string[]): W | null { + + const matches = (uriString: string): boolean => { + return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */)); + }; + + for (const window of windows) { + // match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough + const currPaths = window.extensionDevelopmentPath; + if (currPaths && currPaths.some(p => matches(p))) { + return window; + } + } + + return null; +} + +export function findWindowOnWorkspaceOrFolderUri(windows: W[], uri: URI | undefined): W | null { + if (!uri) { + return null; + } + for (const window of windows) { + // check for workspace config path + if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) { + return window; + } + + // check for folder path + if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) { + return window; + } + } + return null; +} diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/platform/windows/test/node/window.test.ts similarity index 80% rename from src/vs/code/test/node/windowsFinder.test.ts rename to src/vs/platform/windows/test/node/window.test.ts index efabd6407f..6bb4e636ca 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/platform/windows/test/node/window.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; -import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder'; +import { IBestWindowOrFolderOptions, IWindowContext, findBestWindowOrFolderForFile } from 'vs/platform/windows/node/window'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; @@ -20,7 +20,7 @@ const testWorkspace: IWorkspaceIdentifier = { const testWorkspaceFolders = toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath); -function options(custom?: Partial>): IBestWindowOrFolderOptions { +function options(custom?: Partial>): IBestWindowOrFolderOptions { return { windows: [], newWindow: false, @@ -31,10 +31,10 @@ function options(custom?: Partial>): I }; } -const vscodeFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) }; -const lastActiveWindow: ISimpleWindow = { lastFocusTime: 3, openedFolderUri: undefined }; -const noVscodeFolderWindow: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; -const windows: ISimpleWindow[] = [ +const vscodeFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) }; +const lastActiveWindow: IWindowContext = { lastFocusTime: 3, openedFolderUri: undefined }; +const noVscodeFolderWindow: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; +const windows: IWindowContext[] = [ vscodeFolderWindow, lastActiveWindow, noVscodeFolderWindow, @@ -102,7 +102,7 @@ suite('WindowsFinder', () => { windows, fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')) })), vscodeFolderWindow); - const window: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) }; + const window: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window], fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt')) @@ -110,8 +110,8 @@ suite('WindowsFinder', () => { }); test('More specific existing window wins', () => { - const window: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; - const nestedFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) }; + const window: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) }; + const nestedFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window, nestedFolderWindow], fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt')) @@ -119,7 +119,7 @@ suite('WindowsFinder', () => { }); test('Workspace folder wins', () => { - const window: ISimpleWindow = { lastFocusTime: 1, openedWorkspace: testWorkspace }; + const window: IWindowContext = { lastFocusTime: 1, openedWorkspace: testWorkspace }; assert.equal(findBestWindowOrFolderForFile(options({ windows: [window], fileUri: URI.file(path.join(fixturesFolder, 'vscode_workspace_2_folder', 'nested_vscode_folder', 'subfolder', 'file.txt')) diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 65a403464e..08c02ae2ce 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -31,7 +31,7 @@ export interface IWorkspacesService { _serviceBrand: undefined; // Management - enterWorkspace(path: URI): Promise; + enterWorkspace(path: URI): Promise; createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; getWorkspaceIdentifier(workspacePath: URI): Promise; diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 1517db6b64..c90f13ae4c 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -23,6 +23,7 @@ import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; import { exists } from 'vs/base/node/pfs'; import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Disposable } from 'vs/base/common/lifecycle'; export const IWorkspacesHistoryMainService = createDecorator('workspacesHistoryMainService'); @@ -40,7 +41,7 @@ export interface IWorkspacesHistoryMainService { updateWindowsJumpList(): void; } -export class WorkspacesHistoryMainService implements IWorkspacesHistoryMainService { +export class WorkspacesHistoryMainService extends Disposable implements IWorkspacesHistoryMainService { private static readonly MAX_TOTAL_RECENT_ENTRIES = 100; @@ -60,18 +61,27 @@ export class WorkspacesHistoryMainService implements IWorkspacesHistoryMainServi private readonly _onRecentlyOpenedChange = new Emitter(); readonly onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; - private macOSRecentDocumentsUpdater: ThrottledDelayer; + private macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer(800)); constructor( @IStateService private readonly stateService: IStateService, @ILogService private readonly logService: ILogService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleMainService lifecycleMainService: ILifecycleMainService + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService ) { - this.macOSRecentDocumentsUpdater = new ThrottledDelayer(800); + super(); - lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); + this.registerListeners(); + } + + private registerListeners(): void { + + // Install window jump list after opening window + this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); + + // Add to history when entering workspace + this._register(this.workspacesMainService.onWorkspaceEntered(event => this.addRecentlyOpened([{ workspace: event.workspace }]))); } private handleWindowsJumpList(): void { diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index d644c9375f..c2ed8d7ba3 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { join, dirname } from 'vs/base/common/path'; import { mkdirp, writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs'; @@ -17,31 +17,43 @@ import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { Disposable } from 'vs/base/common/lifecycle'; -import { originalFSPath, isEqualOrParent, joinPath } from 'vs/base/common/resources'; +import { originalFSPath, isEqualOrParent, joinPath, isEqual, basename } from 'vs/base/common/resources'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { localize } from 'vs/nls'; +import product from 'vs/platform/product/common/product'; +import { MessageBoxOptions, BrowserWindow } from 'electron'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; +import { findWindowOnWorkspace } from 'vs/platform/windows/node/window'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); +export interface IWorkspaceEnteredEvent { + window: ICodeWindow; + workspace: IWorkspaceIdentifier; +} + export interface IWorkspacesMainService { _serviceBrand: undefined; readonly onUntitledWorkspaceDeleted: Event; + readonly onWorkspaceEntered: Event; + enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise; + + createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier; - resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; - - isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; - + deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void; getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[]; + isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; - - deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; - + resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; getWorkspaceIdentifier(workspacePath: URI): Promise; } @@ -59,9 +71,14 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter()); readonly onUntitledWorkspaceDeleted: Event = this._onUntitledWorkspaceDeleted.event; + private readonly _onWorkspaceEntered = this._register(new Emitter()); + readonly onWorkspaceEntered: Event = this._onWorkspaceEntered.event; + constructor( @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IBackupMainService private readonly backupMainService: IBackupMainService, + @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); @@ -236,6 +253,74 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } return untitledWorkspaces; } + + async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise { + if (!window || !window.win || !window.isReady) { + return null; // return early if the window is not ready or disposed + } + + const isValid = await this.isValidTargetWorkspacePath(window, windows, path); + if (!isValid) { + return null; // return early if the workspace is not valid + } + + const result = this.doEnterWorkspace(window, getWorkspaceIdentifier(path)); + + // Emit as event + this._onWorkspaceEntered.fire({ window, workspace: result.workspace }); + + return result; + } + + private async isValidTargetWorkspacePath(window: ICodeWindow, windows: ICodeWindow[], path?: URI): Promise { + if (!path) { + return true; + } + + if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { + return false; // window is already opened on a workspace with that path + } + + // Prevent overwriting a workspace that is currently opened in another window + if (findWindowOnWorkspace(windows, getWorkspaceIdentifier(path))) { + const options: MessageBoxOptions = { + title: product.nameLong, + type: 'info', + buttons: [localize('ok', "OK")], + message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)), + detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), + noLink: true + }; + + await this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow())); + + return false; + } + + return true; // OK + } + + private doEnterWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult { + window.focus(); + + // Register window for backups and migrate current backups over + let backupPath: string | undefined; + if (!window.config.extensionDevelopmentPath) { + backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath); + } + + // if the window was opened on an untitled workspace, delete it. + if (window.openedWorkspace && this.isUntitledWorkspace(window.openedWorkspace)) { + this.deleteUntitledWorkspaceSync(window.openedWorkspace); + } + + // Update window configuration properly based on transition to workspace + window.config.folderUri = undefined; + window.config.workspace = workspace; + window.config.backupPath = backupPath; + + return { workspace, backupPath }; + } } function getWorkspaceId(configPath: URI): string { diff --git a/src/vs/platform/workspaces/electron-main/workspacesService.ts b/src/vs/platform/workspaces/electron-main/workspacesService.ts index 8f3b205667..b1afbbbcb7 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesService.ts @@ -23,13 +23,13 @@ export class WorkspacesService implements AddFirstParameterToFunctions { + async enterWorkspace(windowId: number, path: URI): Promise { const window = this.windowsMainService.getWindowById(windowId); if (window) { - return this.windowsMainService.enterWorkspace(window, path); + return this.workspacesMainService.enterWorkspace(window, this.windowsMainService.getWindows(), path); } - return undefined; + return null; } createUntitledWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 369bb7e229..f9eaf0c21d 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -18,6 +18,7 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { isWindows } from 'vs/base/common/platform'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { dirname, joinPath } from 'vs/base/common/resources'; +import { TestBackupMainService, TestDialogMainService } from 'vs/workbench/test/workbenchTestServices'; suite('WorkspacesMainService', () => { const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice'); @@ -43,7 +44,7 @@ suite('WorkspacesMainService', () => { let service: WorkspacesMainService; setup(async () => { - service = new WorkspacesMainService(environmentService, logService); + service = new WorkspacesMainService(environmentService, logService, new TestBackupMainService(), new TestDialogMainService()); // Delete any existing backups completely and then re-create it. await pfs.rimraf(untitledWorkspacesHomePath, pfs.RimRafMode.MOVE); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 39c28034ff..1d620dd34b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1085,45 +1085,7 @@ declare module 'vscode' { //#region Custom editors, mjbvz - export enum WebviewContentState { - /** - * The webview content cannot be modified. - * - * This disables save. - */ - Readonly = 1, - - /** - * The webview content has not been changed but they can be modified and saved. - */ - Unchanged = 2, - - /** - * The webview content has been changed and can be saved. - */ - Dirty = 3, - } - - export interface WebviewEditorState { - readonly contentState: WebviewContentState; - } - - export interface WebviewPanel { - editorState: WebviewEditorState; - - /** - * Fired when the webview is being saved. - * - * Both `Unchanged` and `Dirty` editors can be saved. - * - * Extensions should call `waitUntil` to signal when the save operation complete - */ - readonly onWillSave: Event<{ waitUntil: (thenable: Thenable) => void }>; - } - export interface WebviewEditor extends WebviewPanel { - // TODO: We likely do not want `editorState` and `onWillSave` enabled for - // resource backed webviews } export interface WebviewEditorProvider { @@ -1168,7 +1130,7 @@ declare module 'vscode' { * * @return A uri that can be used on the client machine. */ - export function resolveExternalUri(target: Uri): Thenable; + export function asExternalUri(target: Uri): Thenable; } //#endregion diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index a761baa83a..3f8801787d 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField } from '../common/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -328,20 +328,20 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha private static _inflateSuggestDto(defaultRange: IRange, data: ISuggestDataDto): modes.CompletionItem { return { - label: data.a, - kind: data.b, - tags: data.n, - detail: data.c, - documentation: data.d, - sortText: data.e, - filterText: data.f, - preselect: data.g, - insertText: typeof data.h === 'undefined' ? data.a : data.h, - insertTextRules: data.i, - range: data.j || defaultRange, - commitCharacters: data.k, - additionalTextEdits: data.l, - command: data.m, + label: data[ISuggestDataDtoField.label], + kind: data[ISuggestDataDtoField.kind], + tags: data[ISuggestDataDtoField.kindModifier], + detail: data[ISuggestDataDtoField.detail], + documentation: data[ISuggestDataDtoField.documentation], + sortText: data[ISuggestDataDtoField.sortText], + filterText: data[ISuggestDataDtoField.filterText], + preselect: data[ISuggestDataDtoField.preselect], + insertText: typeof data.h === 'undefined' ? data[ISuggestDataDtoField.label] : data.h, + insertTextRules: data[ISuggestDataDtoField.insertTextRules], + range: data[ISuggestDataDtoField.range] || defaultRange, + commitCharacters: data[ISuggestDataDtoField.commitCharacters], + additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits], + command: data[ISuggestDataDtoField.command], // not-standard _id: data.x, }; diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index 0bf7ff0c70..ca8b2d2880 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -47,7 +47,7 @@ export class MainThreadWindow implements MainThreadWindowShape { return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling }); } - async $resolveExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { + async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { const uri = URI.revive(uriComponents); const result = await this.openerService.resolveExternalUri(uri, options); return result.resolved; diff --git a/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts index 492d536c28..c363fb9083 100644 --- a/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -11,7 +11,7 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IOpenInWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { IWorkspacesService, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces'; import { Schemas } from 'vs/base/common/network'; @@ -49,7 +49,7 @@ export class OpenFolderAPICommand { if (!uri) { return executor.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg.forceNewWindow }); } - const options: IOpenInWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry }; + const options: IOpenWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry }; uri = URI.revive(uri); const uriToOpen: IWindowOpenable = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri }; return executor.executeCommand('_files.windowOpen', [uriToOpen], options); @@ -75,10 +75,12 @@ interface INewWindowAPICommandOptions { export class NewWindowAPICommand { public static ID = 'vscode.newWindow'; public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise { - return executor.executeCommand('_files.newWindow', { - reuse: options && options.reuseWindow, + const commandOptions: IOpenEmptyWindowOptions = { + forceReuseWindow: options && options.reuseWindow, remoteAuthority: options && options.remoteAuthority - }); + }; + + return executor.executeCommand('_files.newWindow', commandOptions); } } CommandsRegistry.registerCommand({ diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index becb137094..d15c877dbf 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -249,9 +249,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I openExternal(uri: URI) { return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, - resolveExternalUri(uri: URI) { + asExternalUri(uri: URI) { checkProposedApiEnabled(extension); - return extHostWindow.resolveExternalUri(uri, { allowTunneling: !!initData.remote.isRemote }); + return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, get remoteName() { return getRemoteName(initData.remote.authority); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 0af8834891..53d1932dbb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -750,7 +750,7 @@ export interface IOpenUriOptions { export interface MainThreadWindowShape extends IDisposable { $getWindowVisibility(): Promise; $openUri(uri: UriComponents, options: IOpenUriOptions): Promise; - $resolveExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; + $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } // -- extension host @@ -944,21 +944,38 @@ export class IdObject { } } +export const enum ISuggestDataDtoField { + label = 'a', + kind = 'b', + detail = 'c', + documentation = 'd', + sortText = 'e', + filterText = 'f', + preselect = 'g', + insertText = 'h', + insertTextRules = 'i', + range = 'j', + commitCharacters = 'k', + additionalTextEdits = 'l', + command = 'm', + kindModifier = 'n', +} + export interface ISuggestDataDto { - a/* label */: string; - b/* kind */: modes.CompletionItemKind; - c/* detail */?: string; - d/* documentation */?: string | IMarkdownString; - e/* sortText */?: string; - f/* filterText */?: string; - g/* preselect */?: boolean; - h/* insertText */?: string; - i/* insertTextRules */?: modes.CompletionItemInsertTextRule; - j/* range */?: IRange; - k/* commitCharacters */?: string[]; - l/* additionalTextEdits */?: ISingleEditOperation[]; - m/* command */?: modes.Command; - n/* kindModifier */?: modes.CompletionItemTag[]; + [ISuggestDataDtoField.label]: string; + [ISuggestDataDtoField.kind]: modes.CompletionItemKind; + [ISuggestDataDtoField.detail]?: string; + [ISuggestDataDtoField.documentation]?: string | IMarkdownString; + [ISuggestDataDtoField.sortText]?: string; + [ISuggestDataDtoField.filterText]?: string; + [ISuggestDataDtoField.preselect]?: boolean; + [ISuggestDataDtoField.insertText]?: string; + [ISuggestDataDtoField.insertTextRules]?: modes.CompletionItemInsertTextRule; + [ISuggestDataDtoField.range]?: IRange; + [ISuggestDataDtoField.commitCharacters]?: string[]; + [ISuggestDataDtoField.additionalTextEdits]?: ISingleEditOperation[]; + [ISuggestDataDtoField.command]?: modes.Command; + [ISuggestDataDtoField.kindModifier]?: modes.CompletionItemTag[]; // not-standard x?: ChainedCacheId; } diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 663fb6f89e..afcfa22e1e 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -327,6 +327,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio } this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`); + this._logService.flush(); const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); return Promise.all([ diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index a09a616aaf..217f5cf76e 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -724,18 +724,18 @@ class SuggestAdapter { // x: id, // - a: item.label, - b: typeConvert.CompletionItemKind.from(item.kind), - n: item.tags && item.tags.map(typeConvert.CompletionItemTag.from), - c: item.detail, - d: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), - e: item.sortText, - f: item.filterText, - g: item.preselect, - i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, - k: item.commitCharacters, - l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), - m: this._commands.toInternal(item.command, disposables), + [extHostProtocol.ISuggestDataDtoField.label]: item.label, + [extHostProtocol.ISuggestDataDtoField.kind]: typeConvert.CompletionItemKind.from(item.kind), + [extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from), + [extHostProtocol.ISuggestDataDtoField.detail]: item.detail, + [extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), + [extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText, + [extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText, + [extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect, + [extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, + [extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters, + [extHostProtocol.ISuggestDataDtoField.additionalTextEdits]: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), + [extHostProtocol.ISuggestDataDtoField.command]: this._commands.toInternal(item.command, disposables), }; // 'insertText'-logic diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index faa2755c45..7a2e2c5073 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -859,7 +859,7 @@ export namespace SignatureInformation { return { label: info.label, documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined, - parameters: info.parameters && info.parameters.map(ParameterInformation.from) + parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.from) : [] }; } @@ -867,7 +867,7 @@ export namespace SignatureInformation { return { label: info.label, documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation, - parameters: info.parameters && info.parameters.map(ParameterInformation.to) + parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.to) : [] }; } } @@ -878,7 +878,7 @@ export namespace SignatureHelp { return { activeSignature: help.activeSignature, activeParameter: help.activeParameter, - signatures: help.signatures && help.signatures.map(SignatureInformation.from) + signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.from) : [], }; } @@ -886,7 +886,7 @@ export namespace SignatureHelp { return { activeSignature: help.activeSignature, activeParameter: help.activeParameter, - signatures: help.signatures && help.signatures.map(SignatureInformation.to) + signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.to) : [], }; } } @@ -1163,13 +1163,3 @@ export namespace LogLevel { return types.LogLevel.Info; } } -export namespace WebviewContentState { - export function from(state: vscode.WebviewContentState): modes.WebviewContentState { - switch (state) { - case types.WebviewContentState.Readonly: return modes.WebviewContentState.Readonly; - case types.WebviewContentState.Unchanged: return modes.WebviewContentState.Unchanged; - case types.WebviewContentState.Dirty: return modes.WebviewContentState.Dirty; - default: throw new Error('Unknown vscode.WebviewContentState'); - } - } -} diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 9656a0e0d6..fa8880fd28 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -7,19 +7,20 @@ import { Emitter, Event } from 'vs/base/common/event'; import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import * as modes from 'vs/editor/common/modes'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; -import { Disposable, WebviewContentState } from './extHostTypes'; +import { Disposable } from './extHostTypes'; type IconPath = URI | { light: URI, dark: URI }; export class ExtHostWebview implements vscode.Webview { private _html: string; private _isDisposed: boolean = false; + private _hasCalledAsWebviewUri = false; public readonly _onMessageEmitter = new Emitter(); public readonly onDidReceiveMessage: Event = this._onMessageEmitter.event; @@ -28,7 +29,8 @@ export class ExtHostWebview implements vscode.Webview { private readonly _handle: WebviewPanelHandle, private readonly _proxy: MainThreadWebviewsShape, private _options: vscode.WebviewOptions, - private readonly _initData: WebviewInitData + private readonly _initData: WebviewInitData, + private readonly _extensionId: ExtensionIdentifier | undefined, ) { } public dispose() { @@ -36,6 +38,7 @@ export class ExtHostWebview implements vscode.Webview { } public asWebviewUri(resource: vscode.Uri): vscode.Uri { + this._hasCalledAsWebviewUri = true; return asWebviewUri(this._initData, this._handle, resource); } @@ -53,6 +56,12 @@ export class ExtHostWebview implements vscode.Webview { this.assertNotDisposed(); if (this._html !== value) { this._html = value; + if (this._initData.isExtensionDevelopmentDebug && this._extensionId && !this._hasCalledAsWebviewUri) { + if (/(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) { + this._hasCalledAsWebviewUri = true; + console.warn(`${this._extensionId.value} created a webview that appears to use the vscode-resource scheme directly. Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`); + } + } this._proxy.$setHtml(this._handle, value); } } @@ -93,9 +102,6 @@ export class ExtHostWebviewEditor implements vscode.WebviewEditor { private _viewColumn: vscode.ViewColumn | undefined; private _visible: boolean = true; private _active: boolean = true; - private _state: vscode.WebviewEditorState = { - contentState: WebviewContentState.Readonly, - }; _isDisposed: boolean = false; @@ -215,15 +221,6 @@ export class ExtHostWebviewEditor implements vscode.WebviewEditor { this._visible = value; } - public get editorState(): vscode.WebviewEditorState { - return this._state; - } - - public set editorState(newState: vscode.WebviewEditorState) { - this._state = newState; - this._proxy.$setState(this._handle, typeConverters.WebviewContentState.from(newState.contentState)); - } - private readonly _onWillSave = new Emitter<{ waitUntil: (thenable: Thenable) => void }>(); public readonly onWillSave = this._onWillSave.event; @@ -290,7 +287,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { const handle = ExtHostWebviews.newHandle(); this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation); - const webview = new ExtHostWebview(handle, this._proxy, options, this.initData); + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, extension.identifier); const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview); this._webviewPanels.set(handle, panel); return panel; @@ -405,7 +402,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { return Promise.reject(new Error(`No serializer found for '${viewType}'`)); } - const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData); + const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData, undefined); const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(webviewHandle, revivedPanel); return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state)); @@ -432,7 +429,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { this._proxy.$setExtension(handle, extension.identifier, extension.extensionLocation); - const webview = new ExtHostWebview(handle, this._proxy, options, this.initData); + const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, extension.identifier); const revivedPanel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(handle, revivedPanel); return Promise.resolve(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel)); diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index fb64f6e6d1..fd2958617a 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -54,14 +54,14 @@ export class ExtHostWindow implements ExtHostWindowShape { return this._proxy.$openUri(stringOrUri, options); } - async resolveExternalUri(uri: URI, options: IOpenUriOptions): Promise { + async asExternalUri(uri: URI, options: IOpenUriOptions): Promise { if (isFalsyOrWhitespace(uri.scheme)) { return Promise.reject('Invalid scheme - cannot be empty'); } else if (!new Set([Schemas.http, Schemas.https]).has(uri.scheme)) { return Promise.reject(`Invalid scheme '${uri.scheme}'`); } - const result = await this._proxy.$resolveExternalUri(uri, options); + const result = await this._proxy.$asExternalUri(uri, options); return URI.from(result); } } diff --git a/src/vs/workbench/api/common/shared/webview.ts b/src/vs/workbench/api/common/shared/webview.ts index 483ada3454..da8d308328 100644 --- a/src/vs/workbench/api/common/shared/webview.ts +++ b/src/vs/workbench/api/common/shared/webview.ts @@ -7,6 +7,7 @@ import { URI } from 'vs/base/common/uri'; import * as vscode from 'vscode'; export interface WebviewInitData { + readonly isExtensionDevelopmentDebug: boolean; readonly webviewResourceRoot: string; readonly webviewCspSource: string; } diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index d476e88f5e..bbb1a3d66d 100644 --- a/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -10,7 +10,7 @@ import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window'; +import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window'; export interface OpenCommandPipeArgs { type: 'open'; @@ -127,7 +127,7 @@ export class CLIServer { } if (urisToOpen.length) { const waitMarkerFileURI = waitMarkerFilePath ? URI.file(waitMarkerFilePath) : undefined; - const windowOpenArgs: INativeOpenInWindowOptions = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, waitMarkerFileURI }; + const windowOpenArgs: INativeOpenWindowOptions = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, waitMarkerFileURI }; this._commands.executeCommand('_files.windowOpen', urisToOpen, windowOpenArgs); } res.writeHead(200); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 0c5ba0dc85..e3e0cd936b 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -82,6 +82,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { let r: T | null = null; activationTimesBuilder.codeLoadingStart(); this._logService.info(`ExtensionService#loadCommonJSModule ${module.toString(true)}`); + this._logService.flush(); try { r = require.__$__nodeRequire(module.fsPath); } catch (e) { diff --git a/src/vs/workbench/api/worker/extHostLogService.ts b/src/vs/workbench/api/worker/extHostLogService.ts index 8f45b9364f..951a849cbe 100644 --- a/src/vs/workbench/api/worker/extHostLogService.ts +++ b/src/vs/workbench/api/worker/extHostLogService.ts @@ -72,4 +72,6 @@ export class ExtHostLogService extends AbstractLogService implements ILogService this._proxy.$log(this._logFile, LogLevel.Critical, Array.from(arguments)); } } + + flush(): void { } } diff --git a/src/vs/workbench/browser/actions/textInputActions.ts b/src/vs/workbench/browser/actions/textInputActions.ts new file mode 100644 index 0000000000..f4b3b4c572 --- /dev/null +++ b/src/vs/workbench/browser/actions/textInputActions.ts @@ -0,0 +1,100 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IAction, Action } from 'vs/base/common/actions'; +import { localize } from 'vs/nls'; +import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { EventHelper } from 'vs/base/browser/dom'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { isNative } from 'vs/base/common/platform'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; + +export class TextInputActionsProvider extends Disposable implements IWorkbenchContribution { + + private textInputActions: IAction[] = []; + + constructor( + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IClipboardService private readonly clipboardService: IClipboardService + ) { + super(); + + this.createActions(); + + this.registerListeners(); + } + + private createActions(): void { + this.textInputActions.push( + + // Undo/Redo + new Action('undo', localize('undo', "Undo"), undefined, true, async () => document.execCommand('undo')), + new Action('redo', localize('redo', "Redo"), undefined, true, async () => document.execCommand('redo')), + new Separator(), + + // Cut / Copy / Paste + new Action('editor.action.clipboardCutAction', localize('cut', "Cut"), undefined, true, async () => document.execCommand('cut')), + new Action('editor.action.clipboardCopyAction', localize('copy', "Copy"), undefined, true, async () => document.execCommand('copy')), + new Action('editor.action.clipboardPasteAction', localize('paste', "Paste"), undefined, true, async (element: HTMLInputElement | HTMLTextAreaElement) => { + + // Native: paste is supported + if (isNative) { + document.execCommand('paste'); + } + + // Web: paste is not supported due to security reasons + else { + const clipboardText = await this.clipboardService.readText(); + if ( + element instanceof HTMLTextAreaElement || + element instanceof HTMLInputElement + ) { + const selectionStart = element.selectionStart || 0; + const selectionEnd = element.selectionEnd || 0; + + element.value = `${element.value.substring(0, selectionStart)}${clipboardText}${element.value.substring(selectionEnd, element.value.length)}`; + element.selectionStart = selectionStart + clipboardText.length; + element.selectionEnd = element.selectionStart; + } + } + }), + new Separator(), + + // Select All + new Action('editor.action.selectAll', localize('selectAll', "Select All"), undefined, true, async () => document.execCommand('selectAll')) + ); + } + + private registerListeners(): void { + + // Context menu support in input/textarea + this.layoutService.container.addEventListener('contextmenu', e => this.onContextMenu(e)); + + } + + private onContextMenu(e: MouseEvent): void { + if (e.target instanceof HTMLElement) { + const target = e.target; + if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { + EventHelper.stop(e, true); + + this.contextMenuService.showContextMenu({ + getAnchor: () => e, + getActions: () => this.textInputActions, + getActionsContext: () => target, + onHide: () => target.focus() // fixes https://github.com/Microsoft/vscode/issues/52948 + }); + } + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(TextInputActionsProvider, LifecyclePhase.Ready); diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 6ec04a6cd7..35fee36b12 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -135,7 +135,7 @@ abstract class BaseOpenRecentAction extends Action { }); if (pick) { - return this.hostService.openInWindow([pick.openable], { forceNewWindow: keyMods && keyMods.ctrlCmd }); + return this.hostService.openWindow([pick.openable], { forceNewWindow: keyMods && keyMods.ctrlCmd }); } } } @@ -260,7 +260,7 @@ export class NewWindowAction extends Action { } run(): Promise { - return this.hostService.openEmptyWindow(); + return this.hostService.openWindow(); } } diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 479dbceabf..2628b11181 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -297,7 +297,7 @@ export class ResourcesDropHandler { // Open in separate windows if we drop workspaces or just one folder if (toOpen.length > folderURIs.length || folderURIs.length === 1) { - await this.hostService.openInWindow(toOpen, { forceReuseWindow: true }); + await this.hostService.openWindow(toOpen, { forceReuseWindow: true }); } // folders.length > 1: Multiple folders: Create new workspace with folders and open diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index 55815d6bc1..941bba4ea5 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -163,7 +163,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit this._register(this.openWorkspaceButton.onClick(() => { const model = this.editor.getModel(); if (model) { - this.hostService.openInWindow([{ workspaceUri: model.uri }]); + this.hostService.openWindow([{ workspaceUri: model.uri }]); } })); diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 96313c9321..453a42375c 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -34,7 +34,7 @@ export class NoTabsTitleControl extends TitleControl { this.registerContainerListeners(); // Gesture Support - Gesture.addTarget(this.titleContainer); + this._register(Gesture.addTarget(this.titleContainer)); const labelContainer = document.createElement('div'); addClass(labelContainer, 'label-container'); diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 9b341a74b0..f5b74a10f4 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -435,7 +435,7 @@ export class TabsTitleControl extends TitleControl { addClass(tabContainer, 'tab'); // Gesture Support - Gesture.addTarget(tabContainer); + this._register(Gesture.addTarget(tabContainer)); // Tab Border Top const tabBorderTopContainer = document.createElement('div'); diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index b41332dce7..8d5740a839 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -10,6 +10,7 @@ height: 22px; font-size: 12px; display: flex; + overflow: visible; } .monaco-workbench .part.statusbar.status-border-top::after { @@ -52,7 +53,7 @@ .monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { content: ''; position: absolute; - left: calc(50% - 8px); /* 3px (margin) + 5px (padding) = 8px */ + left: calc(50% - 9px); /* 3px (margin) + 5px (padding) + 1px (icon) = 9px */ top: -5px; border-bottom-width: 5px; border-bottom-style: solid; diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index fb724aa2e7..da955a3bd2 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -223,7 +223,7 @@ export abstract class MenubarControl extends Disposable { const ret: IAction = new Action(commandId, unmnemonicLabel(label), undefined, undefined, (event) => { const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey))); - return this.hostService.openInWindow([openable], { + return this.hostService.openWindow([openable], { forceNewWindow: openInNewWindow }); }); diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index 479757e40d..6c94b08bf1 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -91,7 +91,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry if (phase !== LifecyclePhase.Eventually) { // instantiate everything synchronously and blocking for (const ctor of toBeInstantiated) { - instantiationService.createInstance(ctor); + this.safeCreateInstance(instantiationService, ctor); // catch error so that other contributions are still considered } } else { // for the Eventually-phase we instantiate contributions @@ -102,7 +102,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry let instantiateSome = (idle: IdleDeadline) => { while (i < toBeInstantiated.length) { const ctor = toBeInstantiated[i++]; - instantiationService.createInstance(ctor); + this.safeCreateInstance(instantiationService, ctor); // catch error so that other contributions are still considered if (idle.timeRemaining() < 1) { // time is up -> reschedule runWhenIdle(instantiateSome, forcedTimeout); @@ -114,6 +114,14 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry } } } + + private safeCreateInstance(instantiationService: IInstantiationService, ctor: IConstructorSignature0): void { + try { + instantiationService.createInstance(ctor); + } catch (error) { + console.error(`Unable to instantiate workbench contribution ${ctor}.`, error); + } + } } Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry()); diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts index 35fa4dfc91..41c7778dcf 100644 --- a/src/vs/workbench/contrib/customEditor/browser/commands.ts +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -3,7 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Schemas } from 'vs/base/common/network'; +// import { Schemas } from 'vs/base/common/network'; +import { firstOrDefault } from 'vs/base/common/arrays'; import { URI } from 'vs/base/common/uri'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import * as nls from 'vs/nls'; @@ -12,19 +13,18 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService } from 'vs/platform/list/browser/listService'; import { IEditorCommandsContext } from 'vs/workbench/common/editor'; -import { ResourceContextKey } from 'vs/workbench/common/resources'; +// import { ResourceContextKey } from 'vs/workbench/common/resources'; import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { firstOrDefault } from 'vs/base/common/arrays'; const viewCategory = nls.localize('viewCategory', "View"); // #region Open With const OPEN_WITH_COMMAND_ID = 'openWith'; -const OPEN_WITH_TITLE = { value: nls.localize('openWith.title', 'Open With'), original: 'Open With' }; +// const OPEN_WITH_TITLE = { value: nls.localize('openWith.title', 'Open With'), original: 'Open With' }; KeybindingsRegistry.registerCommandAndKeybindingRule({ id: OPEN_WITH_COMMAND_ID, @@ -41,15 +41,15 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { - group: 'navigation', - order: 20, - command: { - id: OPEN_WITH_COMMAND_ID, - title: OPEN_WITH_TITLE, - }, - when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) -}); +// MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { +// group: 'navigation', +// order: 20, +// command: { +// id: OPEN_WITH_COMMAND_ID, +// title: OPEN_WITH_TITLE, +// }, +// when: ResourceContextKey.Scheme.isEqualTo(Schemas.file) +// }); // #endregion diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 7f4e1cae50..885102e57f 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -33,7 +33,7 @@ const defaultEditorId = 'default'; const defaultEditorInfo: CustomEditorInfo = { id: defaultEditorId, - displayName: nls.localize('promptOpenWith.defaultEditor', "Default built-in editor"), + displayName: nls.localize('promptOpenWith.defaultEditor', "VS Code's standard text editor"), selector: [ { filenamePattern: '*' } ], diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index e1bddbd7c5..23b491247a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -445,7 +445,8 @@ background: url('add-dark.svg') center center no-repeat; } -.hc-black .debug-viewlet .debug-action.add-watch-expression { +.hc-black .debug-viewlet .debug-action.add-watch-expression, +.hc-black .debug-viewlet .debug-action.add-function-breakpoint { background: url('add-hc.svg') center center no-repeat; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index 92cccf6e09..6a0f396957 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -527,9 +527,26 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe return false; } - const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); - recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); + recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed, (extensionId) => { + const tip = this._importantExeBasedRecommendations[extensionId]; + + /* __GDPR__ + exeExtensionRecommendations:alreadyInstalled" : { + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, + "exeName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: tip.exeFriendlyName || basename(tip.windowsPath!) }); + + }); + if (recommendationsToSuggest.length === 0) { + return false; + } + + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); if (recommendationsToSuggest.length === 0) { return false; } @@ -763,7 +780,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private async promptRecommendedExtensionForFileType(recommendationsToSuggest: string[], installed: ILocalExtension[]): Promise { - recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); + if (recommendationsToSuggest.length === 0) { + return false; + } + + recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed); if (recommendationsToSuggest.length === 0) { return false; } @@ -919,10 +941,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ); } - private filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] { - + private filterIgnoredOrNotAllowed(recommendationsToSuggest: string[]): string[] { const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); return recommendationsToSuggest.filter(id => { if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { return false; @@ -930,7 +950,17 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (!this.isExtensionAllowedToBeRecommended(id)) { return false; } + return true; + }); + } + + private filterInstalled(recommendationsToSuggest: string[], installed: ILocalExtension[], onAlreadyInstalled?: (id: string) => void): string[] { + const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); + return recommendationsToSuggest.filter(id => { if (installedExtensionsIds.has(id.toLowerCase())) { + if (onAlreadyInstalled) { + onAlreadyInstalled(id); + } return false; } return true; diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 08d8ee22de..88be93a6e3 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -20,7 +20,7 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/brow import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction, ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction, - EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction + EnableAllAction, EnableAllWorkspaceAction, DisableAllAction, DisableAllWorkspaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; @@ -137,13 +137,13 @@ actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: const disableAllAction = new SyncActionDescriptor(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllAction, 'Extensions: Disable All Installed Extensions', ExtensionsLabel); -const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkpsaceAction, DisableAllWorkpsaceAction.ID, DisableAllWorkpsaceAction.LABEL); +const disableAllWorkspaceAction = new SyncActionDescriptor(DisableAllWorkspaceAction, DisableAllWorkspaceAction.ID, DisableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(disableAllWorkspaceAction, 'Extensions: Disable All Installed Extensions for this Workspace', ExtensionsLabel); const enableAllAction = new SyncActionDescriptor(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllAction, 'Extensions: Enable All Extensions', ExtensionsLabel); -const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkpsaceAction, EnableAllWorkpsaceAction.ID, EnableAllWorkpsaceAction.LABEL); +const enableAllWorkspaceAction = new SyncActionDescriptor(EnableAllWorkspaceAction, EnableAllWorkspaceAction.ID, EnableAllWorkspaceAction.LABEL); actionRegistry.registerWorkbenchAction(enableAllWorkspaceAction, 'Extensions: Enable All Extensions for this Workspace', ExtensionsLabel); const checkForUpdatesAction = new SyncActionDescriptor(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 5dcfbf7b87..69fb95166b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -2707,14 +2707,14 @@ export class DisableAllAction extends Action { } } -export class DisableAllWorkpsaceAction extends Action { +export class DisableAllWorkspaceAction extends Action { static readonly ID = 'workbench.extensions.action.disableAllWorkspace'; static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"); constructor( - id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, + id: string = DisableAllWorkspaceAction.ID, label: string = DisableAllWorkspaceAction.LABEL, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService @@ -2759,14 +2759,14 @@ export class EnableAllAction extends Action { } } -export class EnableAllWorkpsaceAction extends Action { +export class EnableAllWorkspaceAction extends Action { static readonly ID = 'workbench.extensions.action.enableAllWorkspace'; static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace"); constructor( - id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL, + id: string = EnableAllWorkspaceAction.ID, label: string = EnableAllWorkspaceAction.LABEL, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 2164daf103..a008db4673 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -698,28 +698,28 @@ export class ExtensionsListView extends ViewletPanel { // {{SQL CARBON EDIT}} - End // Given all recommendations, trims and returns recommendations in the relevant order after filtering out installed extensions - private getTrimmedRecommendations(installedExtensions: IExtension[], value: string, fileBasedRecommendations: IExtensionRecommendation[], otherRecommendations: IExtensionRecommendation[], workpsaceRecommendations: IExtensionRecommendation[]): string[] { + private getTrimmedRecommendations(installedExtensions: IExtension[], value: string, fileBasedRecommendations: IExtensionRecommendation[], otherRecommendations: IExtensionRecommendation[], workspaceRecommendations: IExtensionRecommendation[]): string[] { const totalCount = 8; - workpsaceRecommendations = workpsaceRecommendations + workspaceRecommendations = workspaceRecommendations .filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); fileBasedRecommendations = fileBasedRecommendations.filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) - && workpsaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) + && workspaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); otherRecommendations = otherRecommendations.filter(recommendation => { return !this.isRecommendationInstalled(recommendation, installedExtensions) && fileBasedRecommendations.every(fileBasedRecommendation => fileBasedRecommendation.extensionId !== recommendation.extensionId) - && workpsaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) + && workspaceRecommendations.every(workspaceRecommendation => workspaceRecommendation.extensionId !== recommendation.extensionId) && recommendation.extensionId.toLowerCase().indexOf(value) > -1; }); const otherCount = Math.min(2, otherRecommendations.length); - const fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workpsaceRecommendations.length - otherCount); - const recommendations = workpsaceRecommendations; + const fileBasedCount = Math.min(fileBasedRecommendations.length, totalCount - workspaceRecommendations.length - otherCount); + const recommendations = workspaceRecommendations; recommendations.push(...fileBasedRecommendations.splice(0, fileBasedCount)); recommendations.push(...otherRecommendations.splice(0, otherCount)); diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css index 6ebd114194..36be0b6f78 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css @@ -54,6 +54,10 @@ flex: 1; } +.extensions-viewlet > .extensions .panel-header > .actions.show { + flex: inherit; +} + .extensions-viewlet > .extensions .message-container { padding: 5px 9px 5px 16px; cursor: default; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts index 375b1a10fe..6454389291 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts @@ -134,7 +134,7 @@ class ReportExtensionSlowAction extends Action { // build issue const title = encodeURIComponent('Extension causes high cpu load'); const osVersion = `${os.type()} ${os.arch()} ${os.release()}`; - const message = `:warning: Make sure to **attach** this file from your *home*-directory:\n:warning:\`${path}\`\n\nFind more details here: https://github.com/Microsoft/vscode/wiki/Explain:-extension-causes-high-cpu-load`; + const message = `:warning: Make sure to **attach** this file from your *home*-directory:\n:warning:\`${path}\`\n\nFind more details here: https://github.com/microsoft/vscode/wiki/Explain-extension-causes-high-cpu-load`; const body = encodeURIComponent(`- Issue Type: \`Performance\` - Extension Name: \`${this.extension.name}\` - Extension Version: \`${this.extension.version}\` diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index e5d5aa5cfd..0a2e73cd19 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -636,7 +636,7 @@ export class SaveExtensionHostProfileAction extends Action { }] }); - if (!picked || !picked.filePath || picked.canceled) { + if (!picked || !picked.filePath) { return; } diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index a88d76731b..6ba4fac8f5 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -764,7 +764,7 @@ export class ShowOpenedFileInNewWindow extends Action { const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (fileResource) { if (this.fileService.canHandleResource(fileResource)) { - this.hostService.openInWindow([{ fileUri: fileResource }], { forceNewWindow: true }); + this.hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true }); } else { this.notificationService.info(nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); } diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index 4e48bf9e3a..b407ff167a 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { toResource, IEditorCommandsContext, SideBySideEditor, EditorInput } from 'vs/workbench/common/editor'; // {{SQL CARBON EDIT}} add edit input -import { IWindowOpenable, IOpenInWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -81,7 +81,7 @@ export const ResourceSelectedForCompareContext = new RawContextKey('res export const REMOVE_ROOT_FOLDER_COMMAND_ID = 'removeRootFolder'; export const REMOVE_ROOT_FOLDER_LABEL = nls.localize('removeFolderFromWorkspace', "Remove Folder from Workspace"); -export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpenable[], options?: IOpenInWindowOptions) => { +export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpenable[], options?: IOpenWindowOptions) => { if (Array.isArray(toOpen)) { const hostService = accessor.get(IHostService); const environmentService = accessor.get(IEnvironmentService); @@ -97,13 +97,13 @@ export const openWindowCommand = (accessor: ServicesAccessor, toOpen: IWindowOpe return openable; }); - hostService.openInWindow(toOpen, options); + hostService.openWindow(toOpen, options); } }; export const newWindowCommand = (accessor: ServicesAccessor, options?: IOpenEmptyWindowOptions) => { const hostService = accessor.get(IHostService); - hostService.openEmptyWindow(options); + hostService.openWindow(options); }; // {{SQL CARBON EDIT}} diff --git a/src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg new file mode 100644 index 0000000000..4862c55dbe --- /dev/null +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg new file mode 100644 index 0000000000..05f920b29b --- /dev/null +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-hc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg b/src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg new file mode 100644 index 0000000000..6359b42e62 --- /dev/null +++ b/src/vs/workbench/contrib/files/browser/media/collapse-all-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index be2e844d9e..f45c99095e 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -163,3 +163,16 @@ .hc-black .monaco-workbench .explorer-viewlet .editor-group { line-height: 20px; } + +/* TODO @misolori convert these to use icon font, for the debug viewlet */ +.monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-light.svg") 50% no-repeat; +} + +.vs-dark .monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-dark.svg") 50% no-repeat; +} + +.hc-black .monaco-workbench .explorer-action.collapse-explorer { + background: url("collapse-all-hc.svg") 50% no-repeat; +} diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index a06eb7222d..bf467d53ea 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -54,6 +54,10 @@ export class EmptyView extends ViewletPanel { } renderHeader(container: HTMLElement): void { + const twisties = document.createElement('div'); + DOM.addClasses(twisties, 'twisties', 'codicon', 'codicon-chevron-right'); + container.appendChild(twisties); + const titleContainer = document.createElement('div'); DOM.addClass(titleContainer, 'title'); container.appendChild(titleContainer); diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 9f99d73b74..b85b7b0ecf 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -117,7 +117,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations)); // actions - this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll())); + this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action codicon-collapse-all', true, async () => this.collapseAll())); this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] })); } @@ -341,11 +341,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { markerFocusContextKey.set(focus.elements.some(e => e instanceof Marker)); relatedInformationFocusContextKey.set(focus.elements.some(e => e instanceof RelatedInformation)); })); - const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement())); - this._register(focusTracker.onDidBlur(() => { - markerFocusContextKey.set(false); - relatedInformationFocusContextKey.set(false); - })); const markersNavigator = this._register(new TreeResourceNavigator2(this.tree, { openOnFocus: true })); this._register(Event.debounce(markersNavigator.onDidOpenResource, (last, event) => event, 75, true)(options => { diff --git a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts index ff6acb185d..3a40f56643 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/startupTimings.ts @@ -21,7 +21,6 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { didUseCachedData, ITimerService } from 'vs/workbench/services/timer/electron-browser/timerService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { getEntries } from 'vs/base/common/performance'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; export class StartupTimings implements IWorkbenchContribution { @@ -34,8 +33,7 @@ export class StartupTimings implements IWorkbenchContribution { @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IUpdateService private readonly _updateService: IUpdateService, - @IEnvironmentService private readonly _envService: IEnvironmentService, - @IHostService private readonly _hostService: IHostService + @IEnvironmentService private readonly _envService: IEnvironmentService ) { // this._report().catch(onUnexpectedError); @@ -93,7 +91,7 @@ export class StartupTimings implements IWorkbenchContribution { if (this._lifecycleService.startupKind !== StartupKind.NewWindow) { return false; } - if (await this._hostService.windowCount !== 1) { + if (await this._electronService.getWindowCount() !== 1) { return false; } const activeViewlet = this._viewletService.getActiveViewlet(); diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index c8dad70d68..cf9576ada3 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -16,6 +16,10 @@ color: inherit !important; } +.settings-editor:focus { + outline: none !important; +} + /* header styling */ .settings-editor > .settings-header { box-sizing: border-box; @@ -158,7 +162,7 @@ } .settings-editor > .settings-body .settings-tree-container .monaco-list-row .mouseover .setting-toolbar-container > .monaco-toolbar .codicon-more, -.settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-item.focused .setting-toolbar-container > .monaco-toolbar .codicon-more, +.settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-item-contents.focused .setting-toolbar-container > .monaco-toolbar .codicon-more, .settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-toolbar-container:hover > .monaco-toolbar .codicon-more, .settings-editor > .settings-body .settings-tree-container .monaco-list-row .setting-toolbar-container > .monaco-toolbar .active .codicon-more { opacity: 1; diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index ffb0bf1215..d26257ee93 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -374,7 +374,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon constructor( @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IPreferencesService private readonly preferencesService: IPreferencesService, - @IWorkspaceContextService private readonly workpsaceContextService: IWorkspaceContextService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @ILabelService labelService: ILabelService, @IExtensionService extensionService: IExtensionService, ) { @@ -410,8 +410,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon }); this.updatePreferencesEditorMenuItem(); - this._register(workpsaceContextService.onDidChangeWorkbenchState(() => this.updatePreferencesEditorMenuItem())); - this._register(workpsaceContextService.onDidChangeWorkspaceFolders(() => this.updatePreferencesEditorMenuItemForWorkspaceFolders())); + this._register(workspaceContextService.onDidChangeWorkbenchState(() => this.updatePreferencesEditorMenuItem())); + this._register(workspaceContextService.onDidChangeWorkspaceFolders(() => this.updatePreferencesEditorMenuItemForWorkspaceFolders())); extensionService.whenInstalledExtensionsRegistered() .then(() => { @@ -434,7 +434,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon private updatePreferencesEditorMenuItem() { const commandId = '_workbench.openWorkspaceSettingsEditor'; - if (this.workpsaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !CommandsRegistry.getCommand(commandId)) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && !CommandsRegistry.getCommand(commandId)) { CommandsRegistry.registerCommand(commandId, () => this.preferencesService.openWorkspaceSettings(false)); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { @@ -454,11 +454,11 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon } private updatePreferencesEditorMenuItemForWorkspaceFolders() { - for (const folder of this.workpsaceContextService.getWorkspace().folders) { + for (const folder of this.workspaceContextService.getWorkspace().folders) { const commandId = `_workbench.openFolderSettings.${folder.uri.toString()}`; if (!CommandsRegistry.getCommand(commandId)) { CommandsRegistry.registerCommand(commandId, () => { - if (this.workpsaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { return this.preferencesService.openWorkspaceSettings(false); } else { return this.preferencesService.openFolderSettings(folder.uri, false); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index e845f40ecb..ec83762222 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -204,7 +204,7 @@ export class SettingsEditor2 extends BaseEditor { createEditor(parent: HTMLElement): void { parent.setAttribute('tabindex', '-1'); - this.rootElement = DOM.append(parent, $('.settings-editor')); + this.rootElement = DOM.append(parent, $('.settings-editor', { tabindex: '-1' })); this.createHeader(this.rootElement); this.createBody(this.rootElement); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index b1bd5aa4aa..e4cc6ce58d 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -37,7 +37,7 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, transparent } from 'vs/platform/theme/common/colorRegistry'; import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ITOCEntry } from 'vs/workbench/contrib/preferences/browser/settingsLayout'; @@ -394,15 +394,12 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre }); toolbar.setActions([], this.settingActions)(); - // change icon from ellipsis to gear - let icon = container.querySelector('.codicon-more'); - if (icon) { - (icon).classList.add('codicon-gear'); - } - - const button = container.querySelector('.toolbar-toggle-more'); + const button = container.querySelector('.codicon-more'); if (button) { (button).tabIndex = -1; + + // change icon from ellipsis to gear + (button).classList.add('codicon-gear'); } return toolbar; @@ -416,7 +413,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre const setting = element.setting; DOM.toggleClass(template.containerElement, 'is-configured', element.isConfigured); - DOM.toggleClass(template.containerElement, 'is-expanded', true); template.containerElement.setAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR, element.setting.key); template.containerElement.setAttribute(AbstractSettingRenderer.SETTING_ID_ATTR, element.id); @@ -1219,7 +1215,7 @@ export class SettingTreeRenderers { } showContextMenu(element: SettingsTreeSettingElement, settingDOMElement: HTMLElement): void { - const toolbarElement = settingDOMElement.querySelector('.toolbar-toggle-more'); + const toolbarElement = settingDOMElement.querySelector('.monaco-toolbar'); if (toolbarElement) { this._contextMenuService.showContextMenu({ getActions: () => this.settingActions, @@ -1544,20 +1540,20 @@ export class SettingsTree extends ObjectTree { this.getHTMLElement().classList.add(treeClass); this.disposables.push(attachStyler(themeService, { - listActiveSelectionBackground: 'transparent', + listActiveSelectionBackground: transparent(Color.white, 0), listActiveSelectionForeground: foreground, - listFocusAndSelectionBackground: 'transparent', + listFocusAndSelectionBackground: transparent(Color.white, 0), listFocusAndSelectionForeground: foreground, - listFocusBackground: 'transparent', + listFocusBackground: transparent(Color.white, 0), listFocusForeground: foreground, listHoverForeground: foreground, - listHoverBackground: 'transparent', - listHoverOutline: 'transparent', - listFocusOutline: 'transparent', - listInactiveSelectionBackground: 'transparent', + listHoverBackground: transparent(Color.white, 0), + listHoverOutline: transparent(Color.white, 0), + listFocusOutline: transparent(Color.white, 0), + listInactiveSelectionBackground: transparent(Color.white, 0), listInactiveSelectionForeground: foreground, - listInactiveFocusBackground: 'transparent', - listInactiveFocusOutline: 'transparent' + listInactiveFocusBackground: transparent(Color.white, 0), + listInactiveFocusOutline: transparent(Color.white, 0) }, colors => { this.style(colors); })); diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index e99f01e0ad..c9fda273b2 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -26,6 +26,7 @@ interface IConfiguration extends IWindowsConfiguration { telemetry: { enableCrashReporter: boolean }; workbench: { list: { horizontalScrolling: boolean } }; debug: { console: { wordWrap: boolean } }; + configurationSync: { enableAuth: boolean }; } export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { @@ -38,6 +39,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private enableCrashReporter: boolean | undefined; private treeHorizontalScrolling: boolean | undefined; private debugConsoleWordWrap: boolean | undefined; + private enableConfigSyncAuth: boolean | undefined; constructor( @IHostService private readonly hostService: IHostService, @@ -105,6 +107,12 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo } } + // Configuration Sync Auth + if (config.configurationSync && typeof config.configurationSync.enableAuth === 'boolean' && config.configurationSync.enableAuth !== this.enableConfigSyncAuth) { + this.enableConfigSyncAuth = config.configurationSync.enableAuth; + changed = true; + } + // Notify only when changed and we are the focused window (avoids notification spam across windows) if (notify && changed) { this.doConfirm( diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 8ef85ab67a..1bb6ece177 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -91,7 +91,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc menu: { menuId: MenuId.CommandPalette }, - handler: (_accessor) => this.remoteAuthority && hostService.openEmptyWindow({ reuse: true }) + handler: (_accessor) => this.remoteAuthority && hostService.openWindow({ forceReuseWindow: true }) }); // Pending entry until extensions are ready diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 5f7bcaf007..46f366fd42 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -554,7 +554,7 @@ export class SearchView extends ViewletPanel { return nls.localize('replaceAll.occurrence.file.message', "Replaced {0} occurrence across {1} file with '{2}'.", occurrences, fileCount, replaceValue); } - return nls.localize('removeAll.occurrence.file.message', "Replaced {0} occurrence across {1} file'.", occurrences, fileCount); + return nls.localize('removeAll.occurrence.file.message', "Replaced {0} occurrence across {1} file.", occurrences, fileCount); } if (replaceValue) { @@ -569,7 +569,7 @@ export class SearchView extends ViewletPanel { return nls.localize('replaceAll.occurrences.file.message', "Replaced {0} occurrences across {1} file with '{2}'.", occurrences, fileCount, replaceValue); } - return nls.localize('removeAll.occurrences.file.message', "Replaced {0} occurrences across {1} file'.", occurrences, fileCount); + return nls.localize('removeAll.occurrences.file.message', "Replaced {0} occurrences across {1} file.", occurrences, fileCount); } if (replaceValue) { @@ -586,7 +586,7 @@ export class SearchView extends ViewletPanel { return nls.localize('removeAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file with '{2}'?", occurrences, fileCount, replaceValue); } - return nls.localize('replaceAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file'?", occurrences, fileCount); + return nls.localize('replaceAll.occurrence.file.confirmation.message', "Replace {0} occurrence across {1} file?", occurrences, fileCount); } if (replaceValue) { @@ -601,7 +601,7 @@ export class SearchView extends ViewletPanel { return nls.localize('removeAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file with '{2}'?", occurrences, fileCount, replaceValue); } - return nls.localize('replaceAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file'?", occurrences, fileCount); + return nls.localize('replaceAll.occurrences.file.confirmation.message', "Replace {0} occurrences across {1} file?", occurrences, fileCount); } if (replaceValue) { diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index 16b55d423b..4f564eef8d 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -454,7 +454,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{ label: localize('openWorkspace', "Open Workspace"), - run: () => this.hostService.openInWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) + run: () => this.hostService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }]) }], { neverShowAgain }); } @@ -467,7 +467,7 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)), { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => { if (pick) { - this.hostService.openInWindow([{ workspaceUri: joinPath(folder, pick.label) }]); + this.hostService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]); } }); } diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 9eaddd1ee0..958847fd99 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -13,7 +13,6 @@ import { Action } from 'vs/base/common/actions'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as Types from 'vs/base/common/types'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { TerminateResponseCode } from 'vs/base/common/processes'; import * as strings from 'vs/base/common/strings'; import { ValidationStatus, ValidationState } from 'vs/base/common/parsers'; @@ -28,7 +27,6 @@ import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configur import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ProblemMatcherRegistry, NamedProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IProgressService, IProgressOptions, ProgressLocation } from 'vs/platform/progress/common/progress'; @@ -354,13 +352,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.runBuildCommand(); }); - KeybindingsRegistry.registerKeybindingRule({ - id: 'workbench.action.tasks.build', - weight: KeybindingWeight.WorkbenchContrib, - when: undefined, - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_B - }); - CommandsRegistry.registerCommand('workbench.action.tasks.test', () => { if (!this.canRunCommand()) { return; diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 8bb78cbf1c..bdff834733 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -33,6 +33,8 @@ import { QuickOpenActionContributor } from '../browser/quickOpen'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { RunAutomaticTasks, ManageAutomaticTaskRunning } from 'vs/workbench/contrib/tasks/browser/runAutomaticTasks'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; let tasksCategory = nls.localize('tasksCategory', "Tasks"); @@ -233,6 +235,13 @@ MenuRegistry.addCommand({ id: 'workbench.action.tasks.configureDefaultTestTask', // MenuRegistry.addCommand( { id: 'workbench.action.tasks.rebuild', title: nls.localize('RebuildAction.label', 'Run Rebuild Task'), category: tasksCategory }); // MenuRegistry.addCommand( { id: 'workbench.action.tasks.clean', title: nls.localize('CleanAction.label', 'Run Clean Task'), category: tasksCategory }); +KeybindingsRegistry.registerKeybindingRule({ + id: 'workbench.action.tasks.build', + weight: KeybindingWeight.WorkbenchContrib, + when: undefined, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_B +}); + // Tasks Output channel. Register it before using it in Task Service. let outputChannelRegistry = Registry.as(OutputExt.OutputChannels); outputChannelRegistry.registerChannel({ id: AbstractTaskService.OutputChannelId, label: AbstractTaskService.OutputChannelLabel, log: false }); diff --git a/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js b/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js index 59edaba961..07f7d132d5 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js +++ b/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js @@ -13,6 +13,15 @@ return; } hasRegistered = true; + + // @ts-ignore + require('electron').webFrame.registerURLSchemeAsPrivileged('vscode-resource', { + secure: true, + bypassCSP: false, + allowServiceWorkers: false, + supportFetchAPI: true, + corsEnabled: true + }); }; }()); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts index 89380ee15d..db844f2a36 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts @@ -4,22 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Registry } from 'vs/platform/registry/common/platform'; -import { TelemetryOptOut } from './telemetryOptOut'; +import { BrowserTelemetryOptOut } from 'vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -// {{SQL CARBON EDIT}} - Add preview feature switch -import { EnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures'; // {{SQL CARBON EDIT}} // Registry // .as(WorkbenchExtensions.Workbench) // .registerWorkbenchContribution(GettingStarted, LifecyclePhase.Running); -Registry - .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(TelemetryOptOut, LifecyclePhase.Eventually); - -// {{SQL CARBON EDIT}} - Add preview feature switch -Registry - .as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(EnablePreviewFeatures, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BrowserTelemetryOptOut, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts index 94fe91907e..64323f2b22 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut.ts @@ -19,7 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IProductService } from 'vs/platform/product/common/productService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -export class TelemetryOptOut implements IWorkbenchContribution { +export abstract class AbstractTelemetryOptOut implements IWorkbenchContribution { private static TELEMETRY_OPT_OUT_SHOWN = 'workbench.telemetryOptOutShown'; private privacyUrl: string | undefined; @@ -35,18 +35,18 @@ export class TelemetryOptOut implements IWorkbenchContribution { @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, @IProductService productService: IProductService ) { - if (!productService.telemetryOptOutUrl || storageService.get(TelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, StorageScope.GLOBAL)) { + if (!productService.telemetryOptOutUrl || storageService.get(AbstractTelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, StorageScope.GLOBAL)) { return; } const experimentId = 'telemetryOptOut'; Promise.all([ - hostService.windowCount, + this.getWindowCount(), experimentService.getExperimentById(experimentId) ]).then(([count, experimentState]) => { if (!hostService.hasFocus && count > 1) { return; } - storageService.store(TelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, true, StorageScope.GLOBAL); + storageService.store(AbstractTelemetryOptOut.TELEMETRY_OPT_OUT_SHOWN, true, StorageScope.GLOBAL); this.privacyUrl = productService.privacyStatementUrl || productService.telemetryOptOutUrl; @@ -74,6 +74,8 @@ export class TelemetryOptOut implements IWorkbenchContribution { .then(undefined, onUnexpectedError); } + protected abstract getWindowCount(): Promise; + private runExperiment(experimentId: string) { const promptMessageKey = 'telemetryOptOut.optOutOption'; const yesLabelKey = 'telemetryOptOut.OptIn'; @@ -148,3 +150,10 @@ export class TelemetryOptOut implements IWorkbenchContribution { }); } } + +export class BrowserTelemetryOptOut extends AbstractTelemetryOptOut { + + protected async getWindowCount(): Promise { + return 1; + } +} diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts new file mode 100644 index 0000000000..e7d562aca3 --- /dev/null +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { NativeTelemetryOptOut } from 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut'; +import { OpenWelcomePageInBrowser } from 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite'; + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(OpenWelcomePageInBrowser, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeTelemetryOptOut, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts new file mode 100644 index 0000000000..1d7c6d6be8 --- /dev/null +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { AbstractTelemetryOptOut } from 'vs/workbench/contrib/welcome/gettingStarted/browser/telemetryOptOut'; +import { IElectronService } from 'vs/platform/electron/node/electron'; + +export class NativeTelemetryOptOut extends AbstractTelemetryOptOut { + + constructor( + @IStorageService storageService: IStorageService, + @IOpenerService openerService: IOpenerService, + @INotificationService notificationService: INotificationService, + @IHostService hostService: IHostService, + @ITelemetryService telemetryService: ITelemetryService, + @IExperimentService experimentService: IExperimentService, + @IConfigurationService configurationService: IConfigurationService, + @IExtensionGalleryService galleryService: IExtensionGalleryService, + @IProductService productService: IProductService, + @IElectronService private readonly electronService: IElectronService + ) { + super(storageService, openerService, notificationService, hostService, telemetryService, experimentService, configurationService, galleryService, productService); + } + + protected getWindowCount(): Promise { + return this.electronService.getWindowCount(); + } +} diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 7cdfdc963a..3b2345a212 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -370,7 +370,7 @@ class WelcomePage extends Disposable { id: 'openRecentFolder', from: telemetryFrom }); - this.hostService.openInWindow([windowOpenable], { forceNewWindow: e.ctrlKey || e.metaKey }); + this.hostService.openWindow([windowOpenable], { forceNewWindow: e.ctrlKey || e.metaKey }); e.preventDefault(); e.stopPropagation(); }); diff --git a/src/vs/workbench/electron-browser/actions/workspaceActions.ts b/src/vs/workbench/electron-browser/actions/workspaceActions.ts index 11426143b0..471e3cd55d 100644 --- a/src/vs/workbench/electron-browser/actions/workspaceActions.ts +++ b/src/vs/workbench/electron-browser/actions/workspaceActions.ts @@ -65,6 +65,6 @@ export class DuplicateWorkspaceInNewWindowAction extends Action { const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); - return this.hostService.openInWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); + return this.hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); } } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 690a1c022c..83600062ec 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -9,13 +9,12 @@ import * as errors from 'vs/base/common/errors'; import { equals, deepClone, assign } from 'vs/base/common/objects'; import * as DOM from 'vs/base/browser/dom'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IAction, Action } from 'vs/base/common/actions'; +import { IAction } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { toResource, IUntitledResourceInput, SideBySideEditor, pathsToEditors } from 'vs/workbench/common/editor'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IRunKeybindingInWindowRequest, getTitleBarStyle } from 'vs/platform/windows/common/windows'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as browser from 'vs/base/browser/browser'; @@ -62,17 +61,6 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; -const TextInputActions: IAction[] = [ - new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), - new Action('redo', nls.localize('redo', "Redo"), undefined, true, () => Promise.resolve(document.execCommand('redo'))), - new Separator(), - new Action('editor.action.clipboardCutAction', nls.localize('cut', "Cut"), undefined, true, () => Promise.resolve(document.execCommand('cut'))), - new Action('editor.action.clipboardCopyAction', nls.localize('copy', "Copy"), undefined, true, () => Promise.resolve(document.execCommand('copy'))), - new Action('editor.action.clipboardPasteAction', nls.localize('paste', "Paste"), undefined, true, () => Promise.resolve(document.execCommand('paste'))), - new Separator(), - new Action('editor.action.selectAll', nls.localize('selectAll', "Select All"), undefined, true, () => Promise.resolve(document.execCommand('selectAll'))) -]; - export class ElectronWindow extends Disposable { private touchBarMenu: IMenu | undefined; @@ -96,7 +84,6 @@ export class ElectronWindow extends Disposable { @INotificationService private readonly notificationService: INotificationService, @ICommandService private readonly commandService: ICommandService, @IKeybindingService private readonly keybindingService: IKeybindingService, - @IContextMenuService private readonly contextMenuService: IContextMenuService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, @IFileService private readonly fileService: IFileService, @@ -239,9 +226,6 @@ export class ElectronWindow extends Disposable { } })); - // Context menu support in input/textarea - window.document.addEventListener('contextmenu', e => this.onContextMenu(e)); - // Listen to visible editor changes this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); @@ -300,21 +284,6 @@ export class ElectronWindow extends Disposable { } } - private onContextMenu(e: MouseEvent): void { - if (e.target instanceof HTMLElement) { - const target = e.target; - if (target.nodeName && (target.nodeName.toLowerCase() === 'input' || target.nodeName.toLowerCase() === 'textarea')) { - DOM.EventHelper.stop(e, true); - - this.contextMenuService.showContextMenu({ - getAnchor: () => e, - getActions: () => TextInputActions, - onHide: () => target.focus() // fixes https://github.com/Microsoft/vscode/issues/52948 - }); - } - } - } - private updateWindowZoomLevel(): void { const windowConfig: IWindowsConfiguration = this.configurationService.getValue(); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index eda895a96f..d8ef677c4b 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -75,9 +75,10 @@ class DecorationRule { } // bubble badge + // TODO @misolori update bubble badge to use class name instead of unicode createCSSRule( `.${this.bubbleBadgeClassName}::after`, - `content: "\uf052"; color: ${getColor(theme, color)}; font-family: octicons; font-size: 14px; padding-right: 14px; opacity: 0.4;`, + `content: "\uf052"; color: ${getColor(theme, color)}; font-family: octicons; font-size: 14px; padding-right: 10px; opacity: 0.4;`, element ); } diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index 5a712c824b..1c1bb348b9 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -91,7 +91,7 @@ export abstract class AbstractFileDialogService { const toOpen: IWindowOpenable = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; if (stat.isDirectory || options.forceNewWindow || preferNewWindow) { - return this.hostService.openInWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); } else { return this.openerService.open(uri); } @@ -105,7 +105,7 @@ export abstract class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { if (options.forceNewWindow || preferNewWindow) { - return this.hostService.openInWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); } else { return this.openerService.open(uri); } @@ -118,7 +118,7 @@ export abstract class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); if (uri) { - return this.hostService.openInWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); } } @@ -129,7 +129,7 @@ export abstract class AbstractFileDialogService { const uri = await this.pickResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }); if (uri) { - return this.hostService.openInWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); + return this.hostService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); } } diff --git a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts index 53df7ddf1b..1f7a567730 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts @@ -110,7 +110,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil return this.pickFileToSaveSimplified(schema, options); } else { const result = await this.electronService.showSaveDialog(this.toNativeSaveDialogOptions(options)); - if (result && !result.canceled && result.filePath) { + if (result && result.filePath) { return URI.file(result.filePath); } } @@ -134,7 +134,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil } const result = await this.electronService.showSaveDialog(this.toNativeSaveDialogOptions(options)); - if (result && !result.canceled && result.filePath) { + if (result && result.filePath) { return URI.file(result.filePath); } diff --git a/src/vs/workbench/services/extensions/common/rpcProtocol.ts b/src/vs/workbench/services/extensions/common/rpcProtocol.ts index f0ebba3ab0..593c6311d0 100644 --- a/src/vs/workbench/services/extensions/common/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/common/rpcProtocol.ts @@ -364,12 +364,16 @@ export class RPCProtocol extends Disposable implements IRPCProtocol { const pendingReply = this._pendingRPCReplies[callId]; delete this._pendingRPCReplies[callId]; - let err: Error | null = null; - if (value && value.$isError) { - err = new Error(); - err.name = value.name; - err.message = value.message; - err.stack = value.stack; + let err: any = undefined; + if (value) { + if (value.$isError) { + err = new Error(); + err.name = value.name; + err.message = value.message; + err.stack = value.stack; + } else { + err = value; + } } pendingReply.resolveErr(err); } @@ -725,7 +729,7 @@ class MessageIO { } public static serializeReplyErr(req: number, err: any): VSBuffer { - if (err instanceof Error) { + if (err) { return this._serializeReplyErrEror(req, err); } return this._serializeReplyErrEmpty(req); diff --git a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts index 439a776fa9..d11c7ccb6e 100644 --- a/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts +++ b/src/vs/workbench/services/extensions/test/node/rpcProtocol.test.ts @@ -187,4 +187,17 @@ suite('RPCProtocol', () => { done(null); }); }); + + test('issue #72798: null errors are hard to digest', function (done) { + delegate = (a1: number, a2: number) => { + throw { 'what': 'what' }; + }; + bProxy.$m(4, 1).then((res) => { + assert.fail('unexpected'); + done(null); + }, (err) => { + assert.equal(err.what, 'what'); + done(null); + }); + }); }); diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index bdd550ddd2..28037e1440 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -9,7 +9,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IResourceEditor, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWindowSettings, IWindowOpenable, IOpenInWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, isFileToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { pathsToEditors } from 'vs/workbench/common/editor'; import { IFileService } from 'vs/platform/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -46,13 +46,6 @@ export class BrowserHostService extends Disposable implements IHostService { _serviceBrand: undefined; - //#region Events - - get onDidChangeFocus(): Event { return this._onDidChangeFocus; } - private _onDidChangeFocus: Event; - - //#endregion - private workspaceProvider: IWorkspaceProvider; constructor( @@ -87,11 +80,28 @@ export class BrowserHostService extends Disposable implements IHostService { ); } - //#region Window + get onDidChangeFocus(): Event { return this._onDidChangeFocus; } + private _onDidChangeFocus: Event; - readonly windowCount = Promise.resolve(1); + get hasFocus(): boolean { + return document.hasFocus(); + } - async openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { + async focus(): Promise { + window.focus(); + } + + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(arg1, arg2); + } + + return this.doOpenEmptyWindow(arg1); + } + + private async doOpenWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise { for (let i = 0; i < toOpen.length; i++) { const openable = toOpen[i]; openable.label = openable.label || this.getRecentLabel(openable); @@ -126,7 +136,7 @@ export class BrowserHostService extends Disposable implements IHostService { return this.labelService.getUriLabel(openable.fileUri); } - private shouldReuse(options: IOpenInWindowOptions = {}): boolean { + private shouldReuse(options: IOpenWindowOptions = {}): boolean { const windowConfig = this.configurationService.getValue('window'); const openFolderInNewWindowConfig = (windowConfig && windowConfig.openFoldersInNewWindow) || 'default' /* default */; @@ -138,8 +148,8 @@ export class BrowserHostService extends Disposable implements IHostService { return !openFolderInNewWindow; } - async openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { - this.workspaceProvider.open(undefined, { reuse: options && options.reuse }); + private async doOpenEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { + this.workspaceProvider.open(undefined, { reuse: options && options.forceReuseWindow }); } async toggleFullScreen(): Promise { @@ -176,16 +186,6 @@ export class BrowserHostService extends Disposable implements IHostService { } } - get hasFocus(): boolean { - return document.hasFocus(); - } - - async focus(): Promise { - window.focus(); - } - - //#endregion - async restart(): Promise { this.reload(); } @@ -195,7 +195,7 @@ export class BrowserHostService extends Disposable implements IHostService { } async closeWorkspace(): Promise { - return this.openEmptyWindow({ reuse: true }); + return this.doOpenEmptyWindow({ forceReuseWindow: true }); } } diff --git a/src/vs/workbench/services/host/browser/host.ts b/src/vs/workbench/services/host/browser/host.ts index c7bfc57b39..f85a63713a 100644 --- a/src/vs/workbench/services/host/browser/host.ts +++ b/src/vs/workbench/services/host/browser/host.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; export const IHostService = createDecorator('hostService'); @@ -13,38 +13,13 @@ export interface IHostService { _serviceBrand: undefined; - //#region Events + //#region Focus /** * Emitted when the window focus changes. */ readonly onDidChangeFocus: Event; - //#endregion - - //#region Window - - /** - * The number of windows that belong to the current client session. - */ - readonly windowCount: Promise; - - /** - * Opens the provided array of openables in a window with the provided options. - */ - openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise; - - /** - * Opens an empty window. The optional parameter allows to define if - * a new window should open or the existing one change to an empty. - */ - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise; - - /** - * Switch between fullscreen and normal window. - */ - toggleFullScreen(): Promise; - /** * Find out if the window has focus or not. */ @@ -57,6 +32,28 @@ export interface IHostService { //#endregion + + //#region Window + + /** + * Opens an empty window. The optional parameter allows to define if + * a new window should open or the existing one change to an empty. + */ + openWindow(options?: IOpenEmptyWindowOptions): Promise; + + /** + * Opens the provided array of openables in a window with the provided options. + */ + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + + /** + * Switch between fullscreen and normal window. + */ + toggleFullScreen(): Promise; + + //#endregion + + //#region Lifecycle /** diff --git a/src/vs/workbench/services/host/electron-browser/desktopHostService.ts b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts index cfe46e62d5..b1846bafd3 100644 --- a/src/vs/workbench/services/host/electron-browser/desktopHostService.ts +++ b/src/vs/workbench/services/host/electron-browser/desktopHostService.ts @@ -9,7 +9,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IWindowOpenable, IOpenInWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { IWindowOpenable, IOpenWindowOptions, isFolderToOpen, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { Disposable } from 'vs/base/common/lifecycle'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; @@ -17,16 +17,6 @@ export class DesktopHostService extends Disposable implements IHostService { _serviceBrand: undefined; - //#region Events - - get onDidChangeFocus(): Event { return this._onDidChangeFocus; } - private _onDidChangeFocus: Event = Event.any( - Event.map(Event.filter(this.electronService.onWindowFocus, id => id === this.electronEnvironmentService.windowId), _ => true), - Event.map(Event.filter(this.electronService.onWindowBlur, id => id === this.electronEnvironmentService.windowId), _ => false) - ); - - //#endregion - constructor( @IElectronService private readonly electronService: IElectronService, @ILabelService private readonly labelService: ILabelService, @@ -46,19 +36,31 @@ export class DesktopHostService extends Disposable implements IHostService { this._register(this.onDidChangeFocus(focus => this._hasFocus = focus)); } - //#region Window + get onDidChangeFocus(): Event { return this._onDidChangeFocus; } + private _onDidChangeFocus: Event = Event.any( + Event.map(Event.filter(this.electronService.onWindowFocus, id => id === this.electronEnvironmentService.windowId), _ => true), + Event.map(Event.filter(this.electronService.onWindowBlur, id => id === this.electronEnvironmentService.windowId), _ => false) + ); private _hasFocus: boolean; get hasFocus(): boolean { return this._hasFocus; } - get windowCount(): Promise { return this.electronService.getWindowCount(); } + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + if (Array.isArray(arg1)) { + return this.doOpenWindow(arg1, arg2); + } - openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { + return this.doOpenEmptyWindow(arg1); + } + + private doOpenWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise { if (!!this.environmentService.configuration.remoteAuthority) { toOpen.forEach(openable => openable.label = openable.label || this.getRecentLabel(openable)); } - return this.electronService.openInWindow(toOpen, options); + return this.electronService.openWindow(toOpen, options); } private getRecentLabel(openable: IWindowOpenable): string { @@ -73,8 +75,8 @@ export class DesktopHostService extends Disposable implements IHostService { return this.labelService.getUriLabel(openable.fileUri); } - openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { - return this.electronService.openEmptyWindow(options); + private doOpenEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { + return this.electronService.openWindow(options); } toggleFullScreen(): Promise { @@ -85,8 +87,6 @@ export class DesktopHostService extends Disposable implements IHostService { return this.electronService.focusWindow(); } - //#endregion - restart(): Promise { return this.electronService.relaunch(); } @@ -96,7 +96,7 @@ export class DesktopHostService extends Disposable implements IHostService { } closeWorkspace(): Promise { - return this.electronService.closeWorkpsace(); + return this.electronService.closeWorkspace(); } } diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index d993c51c24..1f08606179 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -16,6 +16,7 @@ import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; +import { findFreePort } from 'vs/base/node/ports'; export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise { const tunnel = new NodeRemoteTunnel(options, tunnelRemotePort); @@ -25,7 +26,7 @@ export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemo class NodeRemoteTunnel extends Disposable implements RemoteTunnel { public readonly tunnelRemotePort: number; - public readonly tunnelLocalPort: number; + public tunnelLocalPort: number; private readonly _options: IConnectionOptions; private readonly _server: net.Server; @@ -47,7 +48,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { this._server.on('connection', this._connectionListener); this.tunnelRemotePort = tunnelRemotePort; - this.tunnelLocalPort = (this._server.listen(0).address()).port; + } public dispose(): void { @@ -58,6 +59,13 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { } public async waitForReady(): Promise { + + // try to get the same port number as the remote port number... + const localPort = await findFreePort(this.tunnelRemotePort, 1, 1000); + + // if that fails, the method above returns 0, which works out fine below... + this.tunnelLocalPort = (this._server.listen(localPort).address()).port; + await this._barrier.wait(); return this; } diff --git a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts index b112e5fa7d..f1a03783c5 100644 --- a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts +++ b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts @@ -57,6 +57,10 @@ export class BrowserTextFileService extends AbstractTextFileService { return false; // dirty with backups: no veto } + + protected async getWindowCount(): Promise { + return 1; // Browser only ever is 1 window + } } registerSingleton(ITextFileService, BrowserTextFileService); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 2de521df65..08a40efe1a 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -39,7 +39,6 @@ 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'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -74,14 +73,13 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @IFileService protected readonly fileService: IFileService, @IUntitledEditorService protected readonly untitledEditorService: IUntitledEditorService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IInstantiationService protected instantiationService: IInstantiationService, + @IInstantiationService protected readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IModeService private readonly modeService: IModeService, @IModelService private readonly modelService: IModelService, @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, @INotificationService private readonly notificationService: INotificationService, @IBackupFileService private readonly backupFileService: IBackupFileService, - @IHostService private readonly hostService: IHostService, @IHistoryService private readonly historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, @@ -180,7 +178,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex case ShutdownReason.CLOSE: if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.configuredHotExit === HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE) { doBackup = true; // backup if a folder is open and onExitAndWindowClose is configured - } else if (await this.hostService.windowCount > 1 || platform.isMacintosh) { + } else if (await this.getWindowCount() > 1 || platform.isMacintosh) { doBackup = false; // do not backup if a window is closed that does not cause quitting of the application } else { doBackup = true; // backup if last window is closed on win/linux where the application quits right after @@ -213,6 +211,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return true; } + protected abstract getWindowCount(): Promise; + private backupAll(dirtyToBackup: URI[]): Promise { // split up between files and untitled diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 3d7ae14169..203403bb27 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -77,10 +77,10 @@ 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 contentEncoding: string; // encoding as reported from disk + private preferredEncoding: string | undefined; // encoding as chosen by the user - private preferredMode: string | undefined; // mode as chosen by the user + private preferredMode: string | undefined; // mode as chosen by the user private versionId: number; private bufferSavedVersionId: number; @@ -107,7 +107,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil constructor( resource: URI, - preferredEncoding: string, + preferredEncoding: string | undefined, preferredMode: string | undefined, @INotificationService private readonly notificationService: INotificationService, @IModeService modeService: IModeService, diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index a60a2c2e57..716cd81100 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -27,9 +27,46 @@ import { Readable } from 'stream'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { ITextSnapshot } from 'vs/editor/common/model'; import { nodeReadableToString, streamToNodeReadable, nodeStreamToVSBufferReadable } from 'vs/base/node/stream'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { IHistoryService } from 'vs/workbench/services/history/common/history'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export class NativeTextFileService extends AbstractTextFileService { + constructor( + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IFileService fileService: IFileService, + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @ILifecycleService lifecycleService: ILifecycleService, + @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService configurationService: IConfigurationService, + @IModeService modeService: IModeService, + @IModelService modelService: IModelService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @INotificationService notificationService: INotificationService, + @IBackupFileService backupFileService: IBackupFileService, + @IHistoryService historyService: IHistoryService, + @IContextKeyService contextKeyService: IContextKeyService, + @IDialogService dialogService: IDialogService, + @IFileDialogService fileDialogService: IFileDialogService, + @IEditorService editorService: IEditorService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + @IElectronService private readonly electronService: IElectronService + ) { + super(contextService, fileService, untitledEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService); + } + private _encoding!: EncodingOracle; get encoding(): EncodingOracle { if (!this._encoding) { @@ -255,6 +292,10 @@ export class NativeTextFileService extends AbstractTextFileService { }); }); } + + protected getWindowCount(): Promise { + return this.electronService.getWindowCount(); + } } export interface IEncodingOverride { diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 5b4a9a6028..e8f21a04d4 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -7,7 +7,7 @@ import * as sinon from 'sinon'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; -import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestHostService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestContextService, TestFileService, TestElectronService } from 'vs/workbench/test/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; @@ -20,7 +20,7 @@ import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/commo import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; class ServiceAccessor { constructor( @@ -30,7 +30,7 @@ class ServiceAccessor { @IWorkspaceContextService public contextService: TestContextService, @IModelService public modelService: ModelServiceImpl, @IFileService public fileService: TestFileService, - @IHostService public hostService: TestHostService + @IElectronService public electronService: TestElectronService ) { } } @@ -424,7 +424,7 @@ suite('Files - TextFileService', () => { } // Set multiple windows if required if (multipleWindows) { - accessor.hostService.windowCount = Promise.resolve(2); + accessor.electronService.windowCount = Promise.resolve(2); } // Set cancel to force a veto if hot exit does not trigger service.setConfirmResult(ConfirmResult.CANCEL); diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index 38a697680a..384b411732 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { virtualMachineHint } from 'vs/base/node/id'; import * as perf from 'vs/base/common/performance'; import * as os from 'os'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -308,7 +308,7 @@ class TimerService implements ITimerService { private _startupMetrics?: Promise; constructor( - @IHostService private readonly _hostService: IHostService, + @IElectronService private readonly _electronService: IElectronService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @@ -380,7 +380,7 @@ class TimerService implements ITimerService { isLatestVersion: Boolean(await this._updateService.isLatestVersion()), didUseCachedData: didUseCachedData(), windowKind: this._lifecycleService.startupKind, - windowCount: await this._hostService.windowCount, + windowCount: await this._electronService.getWindowCount(), viewletId: activeViewlet ? activeViewlet.getId() : undefined, editorIds: this._editorService.visibleEditors.map(input => input.getTypeId()), panelId: activePanel ? activePanel.getId() : undefined, diff --git a/src/vs/workbench/services/url/electron-browser/urlService.ts b/src/vs/workbench/services/url/electron-browser/urlService.ts index 2027a487d2..edb6c6bcdc 100644 --- a/src/vs/workbench/services/url/electron-browser/urlService.ts +++ b/src/vs/workbench/services/url/electron-browser/urlService.ts @@ -13,6 +13,7 @@ import product from 'vs/platform/product/common/product'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; +import { IElectronService } from 'vs/platform/electron/node/electron'; export class RelayURLService extends URLService implements IURLHandler { @@ -21,7 +22,8 @@ export class RelayURLService extends URLService implements IURLHandler { constructor( @IMainProcessService mainProcessService: IMainProcessService, @IOpenerService openerService: IOpenerService, - @IElectronEnvironmentService private electronEnvironmentService: IElectronEnvironmentService + @IElectronEnvironmentService private electronEnvironmentService: IElectronEnvironmentService, + @IElectronService private electronService: IElectronService ) { super(); @@ -52,8 +54,14 @@ export class RelayURLService extends URLService implements IURLHandler { return await this.urlService.open(resource); } - handleURL(uri: URI): Promise { - return super.open(uri); + async handleURL(uri: URI): Promise { + const result = await super.open(uri); + + if (result) { + await this.electronService.focusWindow(); + } + + return result; } } diff --git a/src/vs/workbench/services/workspaces/browser/workspacesService.ts b/src/vs/workbench/services/workspaces/browser/workspacesService.ts index e010e44cde..7bb7a85a96 100644 --- a/src/vs/workbench/services/workspaces/browser/workspacesService.ts +++ b/src/vs/workbench/services/workspaces/browser/workspacesService.ts @@ -113,7 +113,7 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS //#region Workspace Management - enterWorkspace(path: URI): Promise { + enterWorkspace(path: URI): Promise { throw new Error('Untitled workspaces are currently unsupported in Web'); } diff --git a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts index 75d350224a..499d205af5 100644 --- a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts @@ -78,8 +78,7 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi return false; // only care about untitled workspaces to ask for saving } - const windowCount = await this.hostService.windowCount; - + const windowCount = await this.electronService.getWindowCount(); if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { return false; // Windows/Linux: quits when last window is closed, so do not ask then } diff --git a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts index ff41fcb767..5bfdfe2bee 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -18,7 +18,11 @@ suite('ExtHostWebview', () => { const viewType = 'view.type'; const shape = createNoopMainThreadWebviews(); - const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', webviewResourceRoot: '' }); + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspSource: '', + webviewResourceRoot: '', + isExtensionDevelopmentDebug: false, + }); let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined; @@ -52,7 +56,8 @@ suite('ExtHostWebview', () => { const shape = createNoopMainThreadWebviews(); const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', - webviewResourceRoot: 'vscode-resource://{{resource}}' + webviewResourceRoot: 'vscode-resource://{{resource}}', + isExtensionDevelopmentDebug: false, }); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); @@ -92,7 +97,8 @@ suite('ExtHostWebview', () => { const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', - webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit/{{resource}}` + webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit/{{resource}}`, + isExtensionDevelopmentDebug: false, }); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 6f2b5999f4..56f04116a7 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -8,7 +8,7 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { join } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { ConfirmResult, IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions } from 'vs/workbench/common/editor'; @@ -35,7 +35,7 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { MenuBarVisibility, IWindowConfiguration, IWindowOpenable, IOpenInWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { MenuBarVisibility, IWindowConfiguration, IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -70,7 +70,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ViewletDescriptor, Viewlet } from 'vs/workbench/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; -import { isLinux, isMacintosh } from 'vs/base/common/platform'; +import { isLinux, isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; @@ -86,6 +86,11 @@ import { Schemas } from 'vs/base/common/network'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IElectronService } from 'vs/platform/electron/node/electron'; +import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs'; +import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup'; +import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; +import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -199,13 +204,13 @@ export class TestTextFileService extends NativeTextFileService { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, - @IHostService hostService: IHostService, @IHistoryService historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, - @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + @IElectronService electronService: IElectronService ) { super( contextService, @@ -219,13 +224,13 @@ export class TestTextFileService extends NativeTextFileService { environmentService, notificationService, backupFileService, - hostService, historyService, contextKeyService, dialogService, fileDialogService, editorService, - textResourceConfigurationService + textResourceConfigurationService, + electronService ); } @@ -296,6 +301,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IWorkbenchLayoutService, new TestLayoutService()); + instantiationService.stub(IElectronService, new TestElectronService()); instantiationService.stub(IModeService, instantiationService.createInstance(ModeServiceImpl)); instantiationService.stub(IHistoryService, new TestHistoryService()); instantiationService.stub(ITextResourcePropertiesService, new TestTextResourcePropertiesService(configService)); @@ -1309,16 +1315,148 @@ export class TestHostService implements IHostService { readonly hasFocus: boolean = true; readonly onDidChangeFocus: Event = Event.None; - windowCount = Promise.resolve(1); - async restart(): Promise { } async reload(): Promise { } async closeWorkspace(): Promise { } async focus(): Promise { } - async openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise { } - async openInWindow(toOpen: IWindowOpenable[], options?: IOpenInWindowOptions): Promise { } + async openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { } async toggleFullScreen(): Promise { } } + +export class TestElectronService implements IElectronService { + _serviceBrand: undefined; + + onWindowOpen: Event = Event.None; + onWindowMaximize: Event = Event.None; + onWindowUnmaximize: Event = Event.None; + onWindowFocus: Event = Event.None; + onWindowBlur: Event = Event.None; + + windowCount = Promise.resolve(1); + getWindowCount(): Promise { return this.windowCount; } + + async getWindows(): Promise { return []; } + async getActiveWindowId(): Promise { return undefined; } + + openWindow(options?: IOpenEmptyWindowOptions): Promise; + openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; + openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { + throw new Error('Method not implemented.'); + } + + async toggleFullScreen(): Promise { } + async handleTitleDoubleClick(): Promise { } + async isMaximized(): Promise { return true; } + async maximizeWindow(): Promise { } + async unmaximizeWindow(): Promise { } + async minimizeWindow(): Promise { } + async isWindowFocused(): Promise { return true; } + async focusWindow(options?: { windowId?: number | undefined; } | undefined): Promise { } + async showMessageBox(options: Electron.MessageBoxOptions): Promise { throw new Error('Method not implemented.'); } + async showSaveDialog(options: Electron.SaveDialogOptions): Promise { throw new Error('Method not implemented.'); } + async showOpenDialog(options: Electron.OpenDialogOptions): Promise { throw new Error('Method not implemented.'); } + async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickFileAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise { } + async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise { } + async showItemInFolder(path: string): Promise { } + async setRepresentedFilename(path: string): Promise { } + async setDocumentEdited(edited: boolean): Promise { } + async openExternal(url: string): Promise { return false; } + async updateTouchBar(items: { id: string; title: string | { value: string; original: string; }; category?: string | { value: string; original: string; } | undefined; iconLocation?: { dark: UriComponents; light?: { readonly scheme: string; readonly authority: string; readonly path: string; readonly query: string; readonly fragment: string; readonly fsPath: string; with: {}; toString: {}; toJSON: {}; } | undefined; } | undefined; precondition?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; toggled?: { getType: {}; equals: {}; evaluate: {}; serialize: {}; keys: {}; map: {}; negate: {}; } | undefined; }[][]): Promise { } + async newWindowTab(): Promise { } + async showPreviousWindowTab(): Promise { } + async showNextWindowTab(): Promise { } + async moveWindowTabToNewWindow(): Promise { } + async mergeAllWindowTabs(): Promise { } + async toggleWindowTabsBar(): Promise { } + async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; } | undefined): Promise { } + async reload(): Promise { } + async closeWorkspace(): Promise { } + async closeWindow(): Promise { } + async quit(): Promise { } + async openDevTools(options?: Electron.OpenDevToolsOptions | undefined): Promise { } + async toggleDevTools(): Promise { } + async startCrashReporter(options: Electron.CrashReporterStartOptions): Promise { } + async resolveProxy(url: string): Promise { return undefined; } + async openExtensionDevelopmentHostWindow(args: minimist.ParsedArgs, env: IProcessEnvironment): Promise { } +} + +export class TestBackupMainService implements IBackupMainService { + _serviceBrand: undefined; + + isHotExitEnabled(): boolean { + throw new Error('Method not implemented.'); + } + + getWorkspaceBackups(): IWorkspaceBackupInfo[] { + throw new Error('Method not implemented.'); + } + + getFolderBackupPaths(): URI[] { + throw new Error('Method not implemented.'); + } + + getEmptyWindowBackupPaths(): IEmptyWindowBackupInfo[] { + throw new Error('Method not implemented.'); + } + + registerWorkspaceBackupSync(workspace: IWorkspaceBackupInfo, migrateFrom?: string | undefined): string { + throw new Error('Method not implemented.'); + } + + registerFolderBackupSync(folderUri: URI): string { + throw new Error('Method not implemented.'); + } + + registerEmptyWindowBackupSync(backupFolder?: string | undefined, remoteAuthority?: string | undefined): string { + throw new Error('Method not implemented.'); + } + + unregisterWorkspaceBackupSync(workspace: IWorkspaceIdentifier): void { + throw new Error('Method not implemented.'); + } + + unregisterFolderBackupSync(folderUri: URI): void { + throw new Error('Method not implemented.'); + } + + unregisterEmptyWindowBackupSync(backupFolder: string): void { + throw new Error('Method not implemented.'); + } +} + +export class TestDialogMainService implements IDialogMainService { + _serviceBrand: undefined; + + pickFileFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickFolder(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickFile(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + pickWorkspace(options: INativeOpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showMessageBox(options: Electron.MessageBoxOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showSaveDialog(options: Electron.SaveDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } + + showOpenDialog(options: Electron.OpenDialogOptions, window?: Electron.BrowserWindow | undefined): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index d27552d0c1..6e73cf72f1 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -16,6 +16,7 @@ import 'vs/workbench/browser/workbench.contribution'; //#region --- workbench actions +import 'vs/workbench/browser/actions/textInputActions'; import 'vs/workbench/browser/actions/developerActions'; import 'vs/workbench/browser/actions/helpActions'; import 'vs/workbench/browser/actions/layoutActions'; @@ -339,7 +340,6 @@ import 'vs/workbench/contrib/surveys/browser/languageSurveys.contribution'; import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; -import 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution'; // Call Hierarchy import 'vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 7b0a6bf852..cb25874632 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -146,7 +146,7 @@ import 'vs/workbench/contrib/tasks/electron-browser/taskService'; import 'vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution'; // Welcome -import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/openWebsite.contribution'; +import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; // Configuration Exporter import 'vs/workbench/contrib/configExporter/node/configurationExportHelper.contribution'; @@ -164,3 +164,6 @@ import 'sql/workbench/parts/scripting/electron-browser/scripting.contribution'; import 'sql/workbench/parts/queryHistory/electron-browser/queryHistory.contribution'; import 'sql/workbench/parts/commandLine/electron-browser/commandLine.contribution'; + +//getting started +import 'sql/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 52c4f64769..d3f2c6d04e 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -105,4 +105,7 @@ import 'vs/workbench/contrib/terminal/browser/terminalInstanceService'; // Tasks import 'vs/workbench/contrib/tasks/browser/taskService'; +// Welcome +import 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution'; + //#endregion diff --git a/test/electron/index.js b/test/electron/index.js index c26a8fdc65..9e5e46c278 100644 --- a/test/electron/index.js +++ b/test/electron/index.js @@ -9,7 +9,7 @@ const { join } = require('path'); const path = require('path'); const mocha = require('mocha'); const events = require('events'); -// const MochaJUnitReporter = require('mocha-junit-reporter'); +const MochaJUnitReporter = require('mocha-junit-reporter'); const url = require('url'); const defaultReporterName = process.platform === 'win32' ? 'list' : 'spec'; @@ -133,13 +133,12 @@ app.on('ready', () => { if (argv.tfs) { new mocha.reporters.Spec(runner); - // TODO@deepak the mocha Junit reporter seems to cause a hang when running with Electron 6 inside docker container - // new MochaJUnitReporter(runner, { - // reporterOptions: { - // testsuitesTitle: `${argv.tfs} ${process.platform}`, - // mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${argv.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined - // } - // }); + new MochaJUnitReporter(runner, { + reporterOptions: { + testsuitesTitle: `${argv.tfs} ${process.platform}`, + mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${argv.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined + } + }); } else { const reporterPath = path.join(path.dirname(require.resolve('mocha')), 'lib', 'reporters', argv.reporter); let Reporter; diff --git a/test/smoke/package.json b/test/smoke/package.json index be3067a872..aedec3f871 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -19,7 +19,7 @@ "cpx": "^1.5.0", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", - "mocha": "^5.2.0", + "mocha": "^6.1.4", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "ncp": "^2.0.0", diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 221596fc2c..330b02367e 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -62,6 +62,11 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -77,11 +82,23 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" integrity sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94= +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -103,6 +120,13 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" @@ -254,6 +278,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + chalk@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -265,6 +294,15 @@ chalk@0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" +chalk@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -301,6 +339,15 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -314,10 +361,17 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= commander@2.6.0: version "2.6.0" @@ -400,12 +454,12 @@ date-fns@^1.23.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw== -debug@3.1.0, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== +debug@3.2.6, 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.0.0" + ms "^2.1.1" debug@^2.2.0, debug@^2.3.3: version "2.6.9" @@ -414,12 +468,17 @@ debug@^2.2.0, debug@^2.3.3: 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== +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: - ms "^2.1.1" + ms "2.0.0" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decode-uri-component@^0.2.0: version "0.2.0" @@ -431,6 +490,13 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -506,16 +572,51 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0: +es-abstract@^1.5.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" + integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -617,6 +718,20 @@ find-index@^0.1.1: resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ= +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== + dependencies: + is-buffer "~2.0.3" + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -656,6 +771,11 @@ fsevents@^1.0.0: nan "^2.12.1" node-pre-gyp "^0.12.0" +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -670,6 +790,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -697,7 +822,19 @@ glob2base@^0.0.12: dependencies: find-index "^0.1.1" -glob@7.1.2, glob@^7.0.5: +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.5: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -736,6 +873,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -772,10 +914,17 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== htmlparser2@^3.9.2: version "3.9.2" @@ -847,6 +996,16 @@ is-buffer@^1.1.5, is-buffer@~1.1.1: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-buffer@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -861,6 +1020,11 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -963,6 +1127,20 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -973,6 +1151,11 @@ isarray@1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -985,6 +1168,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -1014,16 +1205,36 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + lodash@^4.16.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== +lodash@^4.17.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + lodash@^4.5.1: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -1159,29 +1370,41 @@ mocha-multi-reporters@^1.1.7: debug "^3.1.0" lodash "^4.16.4" -mocha@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== +mocha@^6.1.4: + version "6.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.1.tgz#da941c99437da9bac412097859ff99543969f94c" + integrity sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A== dependencies: + ansi-colors "3.2.3" browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" + debug "3.2.6" diff "3.5.0" escape-string-regexp "1.0.5" - glob "7.1.2" + find-up "3.0.0" + glob "7.1.3" growl "1.10.5" - he "1.1.1" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" minimatch "3.0.4" mkdirp "0.5.1" - supports-color "5.4.0" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.0" + yargs-parser "13.1.1" + yargs-unparser "1.6.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@^2.1.1: +ms@2.1.1, ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== @@ -1222,6 +1445,14 @@ needle@^2.2.1: iconv-lite "^0.4.4" sax "^1.2.4" +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + node-pre-gyp@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" @@ -1295,6 +1526,16 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -1302,6 +1543,24 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1342,6 +1601,25 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -1357,6 +1635,11 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -1485,6 +1768,16 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -1546,7 +1839,12 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -set-blocking@~2.0.0: +semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -1639,6 +1937,11 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -1664,6 +1967,31 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimleft@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -1699,7 +2027,14 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-json-comments@2.0.1, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= @@ -1711,10 +2046,10 @@ subarg@^1.0.0: dependencies: minimist "^1.1.0" -supports-color@5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== dependencies: has-flag "^3.0.0" @@ -1730,6 +2065,13 @@ supports-color@^3.2.3: dependencies: has-flag "^1.0.0" +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + tar@^4: version "4.4.10" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" @@ -1826,13 +2168,34 @@ watch@^1.0.2: exec-sh "^0.2.0" minimist "^1.2.0" -wide-align@^1.1.0: +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3, wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -1843,7 +2206,45 @@ xml@^1.0.0: resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + yallist@^3.0.0, yallist@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@13.1.1, yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.0, yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1"