diff --git a/extensions/configuration-editing/schemas/attachContainer.schema.json b/extensions/configuration-editing/schemas/attachContainer.schema.json index 9cdd3a5f6d3..9fbc5d0fec7 100644 --- a/extensions/configuration-editing/schemas/attachContainer.schema.json +++ b/extensions/configuration-editing/schemas/attachContainer.schema.json @@ -31,6 +31,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -38,6 +39,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." diff --git a/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json index 112b4e48279..436bede2081 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -139,6 +139,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -146,6 +147,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." @@ -518,6 +520,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -525,6 +528,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." @@ -873,6 +877,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -880,6 +885,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." @@ -1194,6 +1200,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -1201,6 +1208,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." @@ -1484,6 +1492,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -1491,6 +1500,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." diff --git a/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json index 14c13a958b3..8297432256d 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -45,6 +45,7 @@ "enum": [ "notify", "openBrowser", + "openBrowserOnce", "openPreview", "silent", "ignore" @@ -52,6 +53,7 @@ "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", + "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser.", "Opens a preview in the same window when the port is automatically forwarded.", "Shows no notification and takes no action when this port is automatically forwarded.", "This port will not be automatically forwarded." diff --git a/package.json b/package.json index db7770e6960..b04537f65d2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.58.0", - "distro": "3476932990519bc1b4527cd20a3c34b25394695b", + "distro": "3f40871687ee049688201394fdb3f90bbe7bcb3c", "author": { "name": "Microsoft Corporation" }, @@ -222,4 +222,4 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4" } -} \ No newline at end of file +} diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index 3f66035c02e..55303d9a556 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -16,7 +16,7 @@ const bootstrapNode = require('./bootstrap-node'); bootstrapNode.removeGlobalNodeModuleLookupPaths(); // Enable ASAR in our forked processes -bootstrap.enableASARSupport(undefined); +bootstrap.enableASARSupport(undefined, false); if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) { bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 73dbf68427c..23d6e05a210 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -82,7 +82,7 @@ } // Enable ASAR support - globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot); + globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot, true); // Get the nls configuration into the process.env as early as possible const nlsConfig = globalThis.MonacoBootstrap.setupNLS(); diff --git a/src/bootstrap.js b/src/bootstrap.js index d75e7633c89..07c93709f3f 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -43,8 +43,9 @@ /** * @param {string | undefined} appRoot + * @param {boolean} alwaysAddASARPath */ - function enableASARSupport(appRoot) { + function enableASARSupport(appRoot, alwaysAddASARPath) { if (!path || !Module || typeof process === 'undefined') { console.warn('enableASARSupport() is only available in node.js environments'); // TODO@sandbox ASAR is currently non-sandboxed only return; @@ -69,12 +70,17 @@ Module._resolveLookupPaths = function (request, parent) { const paths = originalResolveLookupPaths(request, parent); if (Array.isArray(paths)) { + let asarPathAdded = false; for (let i = 0, len = paths.length; i < len; i++) { if (paths[i] === NODE_MODULES_PATH) { + asarPathAdded = true; paths.splice(i, 0, NODE_MODULES_ASAR_PATH); break; } } + if (alwaysAddASARPath && !asarPathAdded) { + paths.push(NODE_MODULES_ASAR_PATH); + } } return paths; diff --git a/src/cli.js b/src/cli.js index 9e70249ec04..001aed02c0f 100644 --- a/src/cli.js +++ b/src/cli.js @@ -17,7 +17,7 @@ bootstrap.avoidMonkeyPatchFromAppInsights(); bootstrapNode.configurePortable(product); // Enable ASAR support -bootstrap.enableASARSupport(undefined); +bootstrap.enableASARSupport(undefined, false); // Signal processes that we got launched as CLI process.env['VSCODE_CLI'] = '1'; diff --git a/src/main.js b/src/main.js index 3c6cfa90f83..f91f7b731d1 100644 --- a/src/main.js +++ b/src/main.js @@ -33,7 +33,7 @@ app.allowRendererProcessReuse = false; const portable = bootstrapNode.configurePortable(product); // Enable ASAR support -bootstrap.enableASARSupport(undefined); +bootstrap.enableASARSupport(undefined, false); // Set userData path before app 'ready' event const args = parseCLIArgs(); diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index f4e2cffb761..a2ab758a208 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -161,12 +161,17 @@ export enum EditorOverride { /** * Displays a picker and allows the user to decide which editor to use */ - PICK = 1, + PICK, /** * Disables overrides */ - DISABLED + DISABLED, + + /** + * Only exclusive overrides are considered + */ + EXCLUSIVE_ONLY } export enum EditorOpenContext { diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index 88dcc0a0a31..0d717c6d901 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -55,7 +55,8 @@ export enum ProvidedOnAutoForward { OpenBrowser = 2, OpenPreview = 3, Silent = 4, - Ignore = 5 + Ignore = 5, + OpenBrowserOnce = 6 } export interface ProvidedPortAttributes { diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 389d8f4f587..c6644120aac 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -61,7 +61,7 @@ export const enum TerminalSettingId { CursorWidth = 'terminal.integrated.cursorWidth', Scrollback = 'terminal.integrated.scrollback', DetectLocale = 'terminal.integrated.detectLocale', - CreationTarget = 'terminal.integrated.creationTarget', + DefaultLocation = 'terminal.integrated.defaultLocation', GpuAcceleration = 'terminal.integrated.gpuAcceleration', RightClickBehavior = 'terminal.integrated.rightClickBehavior', Cwd = 'terminal.integrated.cwd', diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 53d71797fb2..017f4df470a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -2687,7 +2687,8 @@ declare module 'vscode' { OpenBrowser = 2, OpenPreview = 3, Silent = 4, - Ignore = 5 + Ignore = 5, + OpenBrowserOnce = 6 } export class PortAttributes { diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index 9cf68817e11..72d97e02e7c 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -144,7 +144,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { // preserve pre 1.38 behaviour to not make group active when preserveFocus: true // but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633 activation: options.preserveFocus ? EditorActivation.RESTORE : undefined, - override: EditorOverride.DISABLED + override: EditorOverride.EXCLUSIVE_ONLY }; const input: IResourceEditorInput = { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index cff5b2a56c9..b40c6495560 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -3448,5 +3448,6 @@ export enum PortAutoForwardAction { OpenBrowser = 2, OpenPreview = 3, Silent = 4, - Ignore = 5 + Ignore = 5, + OpenBrowserOnce = 6 } diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 0ba9d54a78e..5487dac973f 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -221,6 +221,7 @@ class OnAutoForwardedAction extends Disposable { private lastNotification: INotificationHandle | undefined; private lastShownPort: number | undefined; private doActionTunnels: RemoteTunnel[] | undefined; + private alreadyOpenedOnce: Set = new Set(); constructor(private readonly notificationService: INotificationService, private readonly remoteExplorerService: IRemoteExplorerService, @@ -243,6 +244,13 @@ class OnAutoForwardedAction extends Disposable { const attributes = (await this.remoteExplorerService.tunnelModel.getAttributes([tunnel.tunnelRemotePort]))?.get(tunnel.tunnelRemotePort)?.onAutoForward; this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) onAutoForward action is ${attributes}`); switch (attributes) { + case OnPortForward.OpenBrowserOnce: { + if (this.alreadyOpenedOnce.has(tunnel.localAddress)) { + break; + } + this.alreadyOpenedOnce.add(tunnel.localAddress); + // Intentionally do not break so that the open browser path can be run. + } case OnPortForward.OpenBrowser: { const address = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); await OpenPortInBrowserAction.run(this.remoteExplorerService.tunnelModel, this.openerService, address); diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 1b68b513319..5dfe4a758b8 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -158,10 +158,11 @@ Registry.as(ConfigurationExtensions.Configuration) properties: { 'onAutoForward': { type: 'string', - enum: ['notify', 'openBrowser', 'openPreview', 'silent', 'ignore'], + enum: ['notify', 'openBrowser', 'openBrowserOnce', 'openPreview', 'silent', 'ignore'], enumDescriptions: [ localize('remote.portsAttributes.notify', "Shows a notification when a port is automatically forwarded."), localize('remote.portsAttributes.openBrowser', "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser."), + localize('remote.portsAttributes.openBrowserOnce', "Opens the browser when the port is automatically forwarded, but only the first time the port is forward during a session. Depending on your settings, this could open an embedded browser."), localize('remote.portsAttributes.openPreview', "Opens a preview in the same window when the port is automatically forwarded."), localize('remote.portsAttributes.silent', "Shows no notification and takes no action when this port is automatically forwarded."), localize('remote.portsAttributes.ignore', "This port will not be automatically forwarded.") diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index 434a298e050..c73dcbeba4e 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -188,6 +188,7 @@ class DirtyDiffWidget extends PeekViewWidget { ['originalResourceScheme', this.model.original!.uri.scheme] ]); this.menu = menuService.createMenu(MenuId.SCMChangeContext, contextKeyService); + this._disposables.add(this.menu); this.create(); if (editor.hasModel()) { @@ -258,9 +259,7 @@ class DirtyDiffWidget extends PeekViewWidget { this._disposables.add(createAndFillInActionBarActions(this.menu, { shouldForwardArgs: true }, actions)); this._actionbarWidget!.push(actions.reverse(), { label: false, icon: true }); this._actionbarWidget!.push([next, previous], { label: false, icon: true }); - this._actionbarWidget!.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, async () => { - this.dispose(); - }), { label: false, icon: true }); + this._actionbarWidget!.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => this.dispose()), { label: false, icon: true }); } protected override _getActionBarOptions(): IActionBarOptions { @@ -298,6 +297,7 @@ class DirtyDiffWidget extends PeekViewWidget { }; this.diffEditor = this.instantiationService.createInstance(EmbeddedDiffEditorWidget, container, options, this.editor); + this._disposables.add(this.diffEditor); } override _onWidth(width: number): void { diff --git a/src/vs/workbench/contrib/scm/browser/menus.ts b/src/vs/workbench/contrib/scm/browser/menus.ts index 8580f1134fc..0fcef83e992 100644 --- a/src/vs/workbench/contrib/scm/browser/menus.ts +++ b/src/vs/workbench/contrib/scm/browser/menus.ts @@ -135,7 +135,8 @@ class SCMMenusItem implements IDisposable { } dispose(): void { - this.resourceGroupMenu?.dispose(); + this._resourceGroupMenu?.dispose(); + this._resourceFolderMenu?.dispose(); this.genericResourceMenu?.dispose(); if (this.contextualResourceMenus) { @@ -143,8 +144,6 @@ class SCMMenusItem implements IDisposable { this.contextualResourceMenus.clear(); this.contextualResourceMenus = undefined; } - - this.resourceFolderMenu?.dispose(); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index ad1606b93f3..2dde0e3093b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -2051,7 +2051,7 @@ class TerminalInstanceDragAndDropController extends Disposable implements IDragA } else { path = uri.fsPath; } - } else if (e.dataTransfer.files?.[0].path /* Electron only */) { + } else if (e.dataTransfer.files.length > 0 && e.dataTransfer.files[0].path /* Electron only */) { // Check if the file was dragged from the filesystem path = URI.file(e.dataTransfer.files[0].path).fsPath; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 980d8efebc6..e36b6ef83cd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -739,7 +739,7 @@ export class TerminalService implements ITerminalService { } async showPanel(focus?: boolean): Promise { - if (this.configHelper.config.creationTarget === TerminalLocation.Editor) { + if (this.configHelper.config.defaultLocation === TerminalLocation.Editor) { return; } const pane = this._viewsService.getActiveViewWithId(TERMINAL_VIEW_ID) @@ -887,11 +887,11 @@ export class TerminalService implements ITerminalService { // create split, only valid if there's an active instance instance = this.splitInstance(activeInstance, value.profile, cwd); } else { - instance = this.createTerminal({ target: this.configHelper.config.creationTarget, config: value.profile, cwd }); + instance = this.createTerminal({ target: this.configHelper.config.defaultLocation, config: value.profile, cwd }); } } - if (instance && this.configHelper.config.creationTarget === TerminalLocation.TerminalView) { + if (instance && this.configHelper.config.defaultLocation === TerminalLocation.TerminalView) { this.showPanel(true); this.activeInstance = instance; return instance; @@ -1029,7 +1029,7 @@ export class TerminalService implements ITerminalService { } let instance: ITerminalInstance; - if (options?.target === TerminalLocation.Editor || this.configHelper.config.creationTarget === TerminalLocation.Editor) { + if (options?.target === TerminalLocation.Editor || this.configHelper.config.defaultLocation === TerminalLocation.Editor) { instance = this.createInstance(shellLaunchConfig); this._terminalEditorService.createEditor(instance); this._initInstanceListeners(instance); diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index c3f8ed04bf8..e1c86a6c3a3 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -207,7 +207,7 @@ export interface ITerminalConfiguration { focusMode: 'singleClick' | 'doubleClick'; }, bellDuration: number; - creationTarget: TerminalLocation; + defaultLocation: TerminalLocation; } export const enum TerminalLocation { diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 1a3972dae40..42990a84a47 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -71,15 +71,15 @@ const terminalConfiguration: IConfigurationNode = { default: 'right', description: localize('terminal.integrated.tabs.location', "Controls the location of the terminal tabs, either to the left or right of the actual terminal(s).") }, - [TerminalSettingId.CreationTarget]: { + [TerminalSettingId.DefaultLocation]: { type: 'string', enum: [TerminalLocation.Editor, TerminalLocation.TerminalView], enumDescriptions: [ - localize('terminal.integrated.creationTarget.editor', "Create terminals in the editor"), - localize('terminal.integrated.creationTarget.view', "Create terminals in the terminal view") + localize('terminal.integrated.defaultLocation.editor', "Create terminals in the editor"), + localize('terminal.integrated.defaultLocation.view', "Create terminals in the terminal view") ], default: 'view', - description: localize('terminal.integrated.creationTarget', "Controls where newly created terminals will appear.") + description: localize('terminal.integrated.defaultLocation', "Controls where newly created terminals will appear.") }, [TerminalSettingId.TabsFocusMode]: { type: 'string', diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts index 13f188d8673..8f5292de3b4 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts @@ -12,7 +12,6 @@ const titleTranslated = localize('title', "Title"); export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'walkthroughs', jsonSchema: { - doNotSuggest: true, description: localize('walkthroughs', "Contribute walkthroughs to help users getting started with your extension."), type: 'array', items: { @@ -201,7 +200,6 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo export const startEntriesExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'startEntries', jsonSchema: { - doNotSuggest: true, description: localize('startEntries', "Contribute commands to the `Welcome: New...` picker."), type: 'array', items: { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 5090970e77f..098be584c01 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter, DebounceEmitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -20,6 +20,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { hash } from 'vs/base/common/hash'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { iconRegistry } from 'vs/base/common/codicons'; +import { asArray } from 'vs/base/common/arrays'; class DecorationRule { @@ -212,25 +213,26 @@ class FileDecorationChangeEvent implements IResourceDecorationChangeEvent { private readonly _data = TernarySearchTree.forUris(_uri => true); // events ignore all path casings + constructor(all: URI | URI[]) { + for (let uri of asArray(all)) { + this._data.set(uri, true); + } + } + affectsResource(uri: URI): boolean { return this._data.get(uri) ?? this._data.findSuperstr(uri) !== undefined; } - static debouncer(last: FileDecorationChangeEvent | undefined, current: URI | URI[]): FileDecorationChangeEvent { - if (!last) { - last = new FileDecorationChangeEvent(); - } - if (Array.isArray(current)) { - // many - for (const uri of current) { - last._data.set(uri, true); + static merge(all: (URI | URI[])[]): URI[] { + let res: URI[] = []; + for (let uriOrArray of all) { + if (Array.isArray(uriOrArray)) { + res = res.concat(uriOrArray); + } else { + res.push(uriOrArray); } - } else { - // one - last._data.set(current, true); } - - return last; + return res; } } @@ -357,24 +359,19 @@ export class DecorationsService implements IDecorationsService { declare readonly _serviceBrand: undefined; private readonly _data = new LinkedList(); - private readonly _onDidChangeDecorationsDelayed = new Emitter(); + private readonly _onDidChangeDecorationsDelayed = new DebounceEmitter({ merge: FileDecorationChangeEvent.merge }); private readonly _onDidChangeDecorations = new Emitter(); private readonly _decorationStyles: DecorationStyles; - readonly onDidChangeDecorations: Event = Event.any( - this._onDidChangeDecorations.event, - Event.debounce( - this._onDidChangeDecorationsDelayed.event, - FileDecorationChangeEvent.debouncer, - undefined, undefined - ) - ); + readonly onDidChangeDecorations = this._onDidChangeDecorations.event; constructor( @IThemeService themeService: IThemeService, @IUriIdentityService private readonly _uriIdentityService: IUriIdentityService, ) { this._decorationStyles = new DecorationStyles(themeService); + + this._onDidChangeDecorationsDelayed.event(event => { this._onDidChangeDecorations.fire(new FileDecorationChangeEvent(event)); }); } dispose(): void { diff --git a/src/vs/workbench/services/editor/browser/editorOverrideService.ts b/src/vs/workbench/services/editor/browser/editorOverrideService.ts index 11dca5ecf6f..294b7752e6f 100644 --- a/src/vs/workbench/services/editor/browser/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/browser/editorOverrideService.ts @@ -116,8 +116,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // Resolved the override as much as possible, now find a given editor - const { editor: matchededEditor, conflictingDefault } = this.getEditor(resource, override); - const selectedEditor = matchededEditor; + const { editor: selectedEditor, conflictingDefault } = this.getEditor(resource, override); if (!selectedEditor) { return OverrideStatus.NONE; } @@ -253,7 +252,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride * Given a resource and an override selects the best possible editor * @returns The editor and whether there was another default which conflicted with it */ - private getEditor(resource: URI, override: string | undefined): { editor: RegisteredEditor | undefined, conflictingDefault: boolean } { + private getEditor(resource: URI, override: string | EditorOverride.EXCLUSIVE_ONLY | undefined): { editor: RegisteredEditor | undefined, conflictingDefault: boolean } { const findMatchingEditor = (editors: RegisteredEditors, viewType: string) => { return editors.find((editor) => { if (editor.options && editor.options.canSupportResource !== undefined) { @@ -262,7 +261,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return editor.editorInfo.id === viewType; }); }; - if (override) { + if (override && override !== EditorOverride.EXCLUSIVE_ONLY) { // Specific overried passed in doesn't have to match the resource, it can be anything const registeredEditors = this._registeredEditors; return { @@ -274,12 +273,19 @@ export class EditorOverrideService extends Disposable implements IEditorOverride let editors = this.findMatchingEditors(resource); const associationsFromSetting = this.getAssociationsForResource(resource); - // We only want built-in+ if no user defined setting is found, else we won't override - const possibleEditors = editors.filter(editor => priorityToRank(editor.editorInfo.priority) >= priorityToRank(RegisteredEditorPriority.builtin) && editor.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id); + // We only want minPriority+ if no user defined setting is found, else we won't override + const minPriority = override === EditorOverride.EXCLUSIVE_ONLY ? RegisteredEditorPriority.exclusive : RegisteredEditorPriority.builtin; + const possibleEditors = editors.filter(editor => priorityToRank(editor.editorInfo.priority) >= priorityToRank(minPriority) && editor.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id); + if (possibleEditors.length === 0) { + return { + editor: undefined, + conflictingDefault: false + }; + } // If the editor is exclusive we use that, else use the user setting, else use the built-in+ editor - const selectedViewType = possibleEditors[0]?.editorInfo.priority === RegisteredEditorPriority.exclusive ? - possibleEditors[0]?.editorInfo.id : - associationsFromSetting[0]?.viewType || possibleEditors[0]?.editorInfo.id; + const selectedViewType = possibleEditors[0].editorInfo.priority === RegisteredEditorPriority.exclusive ? + possibleEditors[0].editorInfo.id : + associationsFromSetting[0]?.viewType || possibleEditors[0].editorInfo.id; let conflictingDefault = false; if (associationsFromSetting.length === 0 && possibleEditors.length > 1) { diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index cfa49044fb3..d89fe91ee91 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -145,6 +145,7 @@ export function mapHasAddressLocalhostOrAllInterfaces(map: Map, ho export enum OnPortForward { Notify = 'notify', OpenBrowser = 'openBrowser', + OpenBrowserOnce = 'openBrowserOnce', OpenPreview = 'openPreview', Silent = 'silent', Ignore = 'ignore' @@ -328,6 +329,7 @@ export class PortsAttributes extends Disposable { switch (providedAction) { case ProvidedOnAutoForward.Notify: return OnPortForward.Notify; case ProvidedOnAutoForward.OpenBrowser: return OnPortForward.OpenBrowser; + case ProvidedOnAutoForward.OpenBrowserOnce: return OnPortForward.OpenBrowserOnce; case ProvidedOnAutoForward.OpenPreview: return OnPortForward.OpenPreview; case ProvidedOnAutoForward.Silent: return OnPortForward.Silent; case ProvidedOnAutoForward.Ignore: return OnPortForward.Ignore; diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 4e7ebc41a7b..08d9c2e4349 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -14,7 +14,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { isVirtualResource } from 'vs/platform/remote/common/remoteHosts'; +import { getRemoteAuthority, isVirtualResource } from 'vs/platform/remote/common/remoteHosts'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { WorkspaceTrustRequestOptions, IWorkspaceTrustManagementService, IWorkspaceTrustInfo, IWorkspaceTrustUriInfo, IWorkspaceTrustRequestService, IWorkspaceTrustTransitionParticipant, WorkspaceTrustUriResponse } from 'vs/platform/workspace/common/workspaceTrust'; @@ -166,7 +166,6 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork private registerListeners(): void { this._register(this.workspaceService.onDidChangeWorkspaceFolders(async () => await this.updateWorkspaceTrust())); - this._register(this.workspaceService.onDidChangeWorkbenchState(async () => await this.updateWorkspaceTrust())); this._register(this.storageService.onDidChangeValue(async changeEvent => { /* This will only execute if storage was changed by a user action in a separate window */ if (changeEvent.key === this.storageKey && JSON.stringify(this._trustStateInfo) !== JSON.stringify(this.loadTrustInfo())) { @@ -340,6 +339,10 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork return { trusted: true, uri }; } + if (this.isTrustedByRemote(uri)) { + return { trusted: true, uri }; + } + let resultState = false; let maxLength = -1; @@ -368,6 +371,10 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork continue; } + if (this.isTrustedByRemote(uri)) { + continue; + } + const foundItem = this._trustStateInfo.uriTrustInfo.find(trustInfo => this.uriIdentityService.extUri.isEqual(trustInfo.uri, uri)); if (!foundItem) { this._trustStateInfo.uriTrustInfo.push({ uri, trusted: true }); @@ -391,6 +398,18 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork return isVirtualResource(uri) && uri.scheme !== 'vscode-vfs'; } + private isTrustedByRemote(uri: URI): boolean { + if (!this.environmentService.remoteAuthority) { + return false; + } + + if (!this._remoteAuthority) { + return false; + } + + return (getRemoteAuthority(uri) === this._remoteAuthority.authority.authority) && !!this._remoteAuthority.options?.isTrusted; + } + private set isTrusted(value: boolean) { this._isTrusted = value; @@ -530,6 +549,11 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork return { trusted: true, uri }; } + // Uri is trusted automatically by the remote + if (this.isTrustedByRemote(uri)) { + return { trusted: true, uri }; + } + return this.doGetUriTrustInfo(await this.getCanonicalUri(uri)); } diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 70a6032ee5f..cd27178f42a 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -30,6 +30,11 @@ interface IStaticExtension { isBuiltin?: boolean; } +/** + * The id of an extension. It is always ${publisher}.${name}. For example: vscode.csharp. + */ +type ExtensionId = string; + interface ICommonTelemetryPropertiesResolver { (): { [key: string]: any }; } @@ -331,9 +336,11 @@ interface IWorkbenchConstructionOptions { /** * Additional builtin extensions that cannot be uninstalled but only be disabled. - * It can be an Id of an extension published in the Marketplace or location of the extension where it is hosted. + * It can be one of the following: + * - `ExtensionId`: id of the extension that is available in Marketplace + * - `UriComponents`: location of the extension where it is hosted. */ - readonly additionalBuiltinExtensions?: readonly (string | UriComponents)[]; + readonly additionalBuiltinExtensions?: readonly (ExtensionId | UriComponents)[]; /** * Filter for built-in extensions.