diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 756b606fb..cc265cde4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [macos-14] - node-version: [20.x] + node-version: [24.x] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-wtih-vscode-build.yml b/.github/workflows/test-wtih-vscode-build.yml index 01f991ed0..5bc2b0d10 100644 --- a/.github/workflows/test-wtih-vscode-build.yml +++ b/.github/workflows/test-wtih-vscode-build.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [macos-14] - node-version: [22.x] + node-version: [24.x] runs-on: ${{ matrix.os }} diff --git a/package-lock.json b/package-lock.json index bd538ea69..3af5c6c70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "ISC", "devDependencies": { "@cloudflare/workers-types": "^4.20250109.0", - "@github1s/vscode-web": "^0.27.0", + "@github1s/vscode-web": "^0.28.1", "chokidar": "^4.0.3", "clean-css": "^5.3.3", "copy-webpack-plugin": "^14.0.0", @@ -251,9 +251,9 @@ } }, "node_modules/@github1s/vscode-web": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@github1s/vscode-web/-/vscode-web-0.27.0.tgz", - "integrity": "sha512-FC7kPJAqYpNvmBsjSp14OLOSMjKOIxRyRJ8W9FQ5rLBNhQQQ/fVtlhKXBVUKKF64Dl14iEGXdM1+rEDm2XS8Ug==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@github1s/vscode-web/-/vscode-web-0.28.1.tgz", + "integrity": "sha512-dJ2mXQ+/xdBrOcLuqYBKTjmA04Rr8Fg2au+Xu5mL1JgsE+FWe5AA0STgPTvuy8Zu6zdzlRJ7z9LOLzTh8DI6Dw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 2a32d0ebd..264949427 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "license": "ISC", "devDependencies": { "@cloudflare/workers-types": "^4.20250109.0", - "@github1s/vscode-web": "^0.27.0", + "@github1s/vscode-web": "^0.28.1", "chokidar": "^4.0.3", "clean-css": "^5.3.3", "copy-webpack-plugin": "^14.0.0", diff --git a/src/index.ts b/src/index.ts index 89d39c8fb..6f58cc439 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,7 +59,7 @@ globalThis._VSCODE_WEB = { if (!DEV_VSCODE) { const linkElement = document.createElement('link'); linkElement.setAttribute('rel', 'stylesheet'); - linkElement.setAttribute('href', resolveVscodeUrl('vs/workbench/workbench.web.main.css')); + linkElement.setAttribute('href', resolveVscodeUrl('vs/workbench/workbench.web.main.internal.css')); document.head.appendChild(linkElement); const languageId = document.cookie.match(/(^| )vscode.nls.locale=([^;]+)/)?.[2] || ''; diff --git a/vscode-web/.VERSION b/vscode-web/.VERSION index 0eb7b9858..21f81fe80 100644 --- a/vscode-web/.VERSION +++ b/vscode-web/.VERSION @@ -1 +1 @@ -1.109.5 \ No newline at end of file +1.131.0 \ No newline at end of file diff --git a/vscode-web/index.html b/vscode-web/index.html index 92c93eec4..645ace19d 100644 --- a/vscode-web/index.html +++ b/vscode-web/index.html @@ -5,7 +5,7 @@ VSCode Web - + diff --git a/vscode-web/package-lock.json b/vscode-web/package-lock.json index 2ad2c644a..ea17e2ff8 100644 --- a/vscode-web/package-lock.json +++ b/vscode-web/package-lock.json @@ -1,12 +1,12 @@ { "name": "@github1s/vscode-web", - "version": "0.27.0", + "version": "0.28.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@github1s/vscode-web", - "version": "0.27.0", + "version": "0.28.1", "license": "MIT", "devDependencies": { "chokidar": "^4.0.3", diff --git a/vscode-web/package.json b/vscode-web/package.json index 82fc6404b..84004815b 100644 --- a/vscode-web/package.json +++ b/vscode-web/package.json @@ -1,6 +1,6 @@ { "name": "@github1s/vscode-web", - "version": "0.27.0", + "version": "0.28.1", "description": "VS Code web for GitHub1s", "author": "github1s", "license": "MIT", diff --git a/vscode-web/scripts/.patch b/vscode-web/scripts/.patch index 37a0e3efe..5a85a9d63 100644 --- a/vscode-web/scripts/.patch +++ b/vscode-web/scripts/.patch @@ -1,12 +1,11 @@ { - "src/vs/workbench/browser/parts/activitybar/activitybarPart.ts": "3edda05b7b7cf235bc0d51f066aa8d57c447ea784ccd507316327150a4bb880c", - "src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css": "f87409af0f50e021ac0880863da50ccfc738728367228af595675f6d12f1ad1b", - "src/vs/workbench/browser/web.main.ts": "c28f5afce7e37992262b827afcc98b25dc0ea9805fb84bfb3e2641d94ddaa885", + "src/vs/workbench/browser/parts/activitybar/activitybarPart.ts": "1c5075a0d54829eadbb19a214f9913558ddab03c3e088b2ec3590b49b2b8c460", + "src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css": "8ffe6921a1c36709db7ed7f5eb705782f55e90acdc780c7722030b0f9e6d6fc5", + "src/vs/workbench/browser/web.main.ts": "180c4439bcb518402e34c9b8b154bcd204b4b2e47a3edf2b1c77c612a8ff2bf5", "src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts": "e986095a30dbea54af56c25fa1b184b55f34f8914129b27e2f20d8c4ea9fd16b", - "src/vs/workbench/contrib/webview/browser/pre/index.html": "8b2e27b411b4fa493fe003c5312378ca0c7164fee99ed288c6e4f47c43dbca1f", + "src/vs/workbench/contrib/webview/browser/pre/index.html": "9f4a216e3c7abfa81d3afa9e215a36e935eb92b9193ae244cf80b1904d3fae0c", "src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts": "16fc1f8830432097a2de87ba04f9f11e930408df8f672bb7a4bbbe3c1a7c509d", - "src/vs/workbench/services/label/common/labelService.ts": "d9a00bb4644ffdaee5b22261389ade4cc2c0d0c37ba7a46c779f8fb9c7db1866", + "src/vs/workbench/services/label/common/labelService.ts": "9e4e2aafeabc04ccf183b8f2f4ce8a4d39f240831e4005b06149684458caa8d4", "src/vs/workbench/services/textfile/browser/textFileService.ts": "886566605815367d3866be243994829729fd0b85c04ab7450b9de22ee93053eb", - "src/vs/base/common/network.ts": "059af1f9d8671226e6636bed2a28a6d91a15c1a26f5c826336ce0dedacb3cafb", - "src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html": "40d576ad2307d28012b34b86858ba36ba49ae10e5aedb394bd06b14a35b869a5" + "src/vs/base/common/network.ts": "d264af1ba5dbbfaf950c5da336100fb1242802eab92ed3b4692d3c10282b2dee" } \ No newline at end of file diff --git a/vscode-web/scripts/build/vscode.js b/vscode-web/scripts/build/vscode.js index 587e61592..6546f0b1b 100755 --- a/vscode-web/scripts/build/vscode.js +++ b/vscode-web/scripts/build/vscode.js @@ -5,7 +5,8 @@ import { executeCommand, PROJECT_ROOT } from '../utils.js'; const main = () => { const cwd = path.join(PROJECT_ROOT, 'lib/vscode'); - executeCommand('npm', ['run', 'gulp', 'vscode-web-min'], cwd); + executeCommand('npm', ['run', 'gulp', 'core-ci'], cwd); + executeCommand('npm', ['run', 'gulp', 'vscode-web-min-ci'], cwd); }; main(); diff --git a/vscode-web/scripts/utils.js b/vscode-web/scripts/utils.js index 12d275c8a..e42f1ab36 100644 --- a/vscode-web/scripts/utils.js +++ b/vscode-web/scripts/utils.js @@ -9,6 +9,9 @@ export const executeCommand = (command, args, cwd) => { if (result.error) { throw result.error; } + if (result.status !== 0) { + throw new Error(`${command} ${args.join(' ')} exited with code ${result.status}`); + } }; export const getAllFiles = (directory) => { diff --git a/vscode-web/src/vs/base/common/network.ts b/vscode-web/src/vs/base/common/network.ts index 009c1dead..f189cc95f 100644 --- a/vscode-web/src/vs/base/common/network.ts +++ b/vscode-web/src/vs/base/common/network.ts @@ -75,6 +75,9 @@ export namespace Schemas { export const vscodeTerminal = 'vscode-terminal'; + /** Scheme used for the image carousel editor. */ + export const vscodeImageCarousel = 'vscode-image-carousel'; + /** Scheme used for code blocks in chat. */ export const vscodeChatCodeBlock = 'vscode-chat-code-block'; @@ -224,7 +227,7 @@ class RemoteAuthoritiesImpl { try { return this._delegate(uri); } catch (err) { - errors.onUnexpectedError(err); + errors.onUnexpectedExternalError(err); return uri; } } diff --git a/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 36b7914e1..e349efa8e 100644 --- a/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,7 +8,7 @@ import './media/activityaction.css'; import { localize, localize2 } from '../../../../nls.js'; import { ActionsOrientation } from '../../../../base/browser/ui/actionbar/actionbar.js'; import { Part } from '../../part.js'; -import { ActivityBarPosition, IWorkbenchLayoutService, LayoutSettings, Parts, Position } from '../../../services/layout/browser/layoutService.js'; +import { ActivityBarPosition, IWorkbenchLayoutService, LayoutSettings, Parts, Position, FLOATING_PANEL_MARGIN } from '../../../services/layout/browser/layoutService.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { DisposableStore, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { ToggleSidebarPositionAction, ToggleSidebarVisibilityAction } from '../../actions/layoutActions.js'; @@ -31,6 +31,7 @@ import { GlobalCompositeBar } from '../globalCompositeBar.js'; import { IStorageService } from '../../../../platform/storage/common/storage.js'; import { Action2, IMenuService, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IsSessionsWindowContext } from '../../../common/contextkeys.js'; import { Categories } from '../../../../platform/action/common/actionCommonCategories.js'; import { getContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; import { IViewDescriptorService, ViewContainerLocation, ViewContainerLocationToString } from '../../../common/views.js'; @@ -42,6 +43,26 @@ import { SwitchCompositeViewAction } from '../compositeBarActions.js'; export class ActivitybarPart extends Part { static readonly ACTION_HEIGHT = 48; + static readonly COMPACT_ACTION_HEIGHT = 28; + + static readonly ACTIVITYBAR_WIDTH = 48; + static readonly COMPACT_ACTIVITYBAR_WIDTH = 36; + + /** Narrower dimensions used when the floating panels (Modern UI) experiment is enabled. */ + static readonly FLOATING_ACTION_HEIGHT = 36; + static readonly FLOATING_ACTIVITYBAR_WIDTH = 36; + static readonly FLOATING_COMPACT_ACTIVITYBAR_WIDTH = 28; + + static readonly ICON_SIZE = 24; + static readonly COMPACT_ICON_SIZE = 16; + + /** + * Gutter reserved on the left and bottom edges under the floating panels + * experiment so the activity bar aligns with the floating cards (it stays + * flush with the title bar, so no top gutter). Must match the margins applied + * in `part.css` under `.floating-panels`. + */ + static readonly FLOATING_MARGIN = FLOATING_PANEL_MARGIN; static readonly pinnedViewContainersKey = 'workbench.activity.pinnedViewlets2'; static readonly placeholderViewContainersKey = 'workbench.activity.placeholderViewlets'; @@ -49,35 +70,103 @@ export class ActivitybarPart extends Part { //#region IView - readonly minimumWidth: number = 48; - readonly maximumWidth: number = 48; + get minimumWidth(): number { return this.baseWidth + this.floatingGutter; } + get maximumWidth(): number { return this.baseWidth + this.floatingGutter; } readonly minimumHeight: number = 0; readonly maximumHeight: number = Number.POSITIVE_INFINITY; //#endregion + /** The intrinsic activity bar width (excludes any floating gutter). */ + private get baseWidth(): number { + if (this.layoutService.isFloatingPanelsEnabled()) { + return this._isCompact ? ActivitybarPart.FLOATING_COMPACT_ACTIVITYBAR_WIDTH : ActivitybarPart.FLOATING_ACTIVITYBAR_WIDTH; + } + return this._isCompact ? ActivitybarPart.COMPACT_ACTIVITYBAR_WIDTH : ActivitybarPart.ACTIVITYBAR_WIDTH; + } + + /** The action (item) height that drives visible item sizing and the composite bar overflow size. */ + private get actionHeight(): number { + if (this._isCompact) { + return ActivitybarPart.COMPACT_ACTION_HEIGHT; + } + return this.layoutService.isFloatingPanelsEnabled() ? ActivitybarPart.FLOATING_ACTION_HEIGHT : ActivitybarPart.ACTION_HEIGHT; + } + + /** Extra space reserved around the part when the floating panels experiment is enabled. */ + private get floatingGutter(): number { return this.layoutService.isFloatingPanelsEnabled() ? ActivitybarPart.FLOATING_MARGIN : 0; } + private readonly compositeBar = this._register(new MutableDisposable()); private content: HTMLElement | undefined; + private _isCompact: boolean; constructor( + private readonly location: ViewContainerLocation, private readonly paneCompositePart: IPaneCompositePart, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IThemeService themeService: IThemeService, @IStorageService storageService: IStorageService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); + + this._isCompact = this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_COMPACT) ?? false; + + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(LayoutSettings.ACTIVITY_BAR_COMPACT)) { + this._isCompact = this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_COMPACT) ?? false; + this.updateCompactStyle(); + this.recreateCompositeBar(); + this._onDidChange.fire(undefined); // Signal grid that size constraints changed + } + + // Floating panels changes the reserved left/bottom gutter (and therefore + // the fixed part width): signal the grid that the size constraint changed. + if (e.affectsConfiguration(LayoutSettings.MODERN_UI)) { + this.updateCompactStyle(); + this.recreateCompositeBar(); + this._onDidChange.fire(undefined); + } + })); + } + + private updateCompactStyle(): void { + if (this.element) { + this.element.classList.toggle('compact', this._isCompact); + this.element.style.setProperty('--activity-bar-width', `${this.baseWidth}px`); + this.element.style.setProperty('--activity-bar-action-height', `${this.actionHeight}px`); + this.element.style.setProperty('--activity-bar-icon-size', `${this._isCompact ? ActivitybarPart.COMPACT_ICON_SIZE : ActivitybarPart.ICON_SIZE}px`); + } + } + + private recreateCompositeBar(): void { + if (!this.content || !this.compositeBar.value) { + return; + } + + this.compositeBar.clear(); + clearNode(this.content); + this.compositeBar.value = this.createCompositeBar(); + this.compositeBar.value.create(this.content); + + if (this.dimension) { + this.layout(this.dimension.width, this.dimension.height); + } } private createCompositeBar(): PaneCompositeBar { - return this.instantiationService.createInstance(ActivityBarCompositeBar, { + const actionHeight = this.actionHeight; + const iconSize = this._isCompact ? ActivitybarPart.COMPACT_ICON_SIZE : ActivitybarPart.ICON_SIZE; + + return this.instantiationService.createInstance(ActivityBarCompositeBar, this.location, { partContainerClass: 'activitybar', pinnedViewContainersKey: ActivitybarPart.pinnedViewContainersKey, placeholderViewContainersKey: ActivitybarPart.placeholderViewContainersKey, viewContainersWorkspaceStateKey: ActivitybarPart.viewContainersWorkspaceStateKey, orientation: ActionsOrientation.VERTICAL, icon: true, - iconSize: 24, + iconSize, activityHoverOptions: { position: () => this.layoutService.getSideBarPosition() === Position.LEFT ? HoverPosition.RIGHT : HoverPosition.LEFT, }, @@ -95,7 +184,7 @@ export class ActivitybarPart extends Part { dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER), activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined, }), - overflowActionSize: ActivitybarPart.ACTION_HEIGHT, + overflowActionSize: actionHeight, }, Parts.ACTIVITYBAR_PART, this.paneCompositePart, true); } @@ -103,6 +192,8 @@ export class ActivitybarPart extends Part { this.element = parent; this.content = append(this.element, $('.content')); + this.updateCompactStyle(); + if (this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { this.show(); } @@ -176,11 +267,20 @@ export class ActivitybarPart extends Part { return; } + // When the floating panels experiment is enabled, reserve a gutter on the + // left and bottom so the activity bar lines up with the floating cards (it + // stays flush with the title bar, so no top gutter). The grid column is grown + // by the same amount (see minimum/maximumWidth) and the matching margins are + // applied in CSS (`.floating-panels .part.activitybar`). + const gutter = this.floatingGutter; + const contentWidth = Math.max(0, width - gutter); + const contentHeight = Math.max(0, height - gutter); + // Layout contents - const contentAreaSize = super.layoutContents(width, height).contentSize; + const contentAreaSize = super.layoutContents(contentWidth, contentHeight).contentSize; // Layout composite bar - this.compositeBar.value.layout(width, contentAreaSize.height); + this.compositeBar.value.layout(contentWidth, contentAreaSize.height); } toJSON(): object { @@ -202,6 +302,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { private readonly keyboardNavigationDisposables = this._register(new DisposableStore()); constructor( + location: ViewContainerLocation, options: IPaneCompositeBarOptions, part: Parts, paneCompositePart: IPaneCompositePart, @@ -217,13 +318,14 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { @IMenuService private readonly menuService: IMenuService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, ) { - super({ - ...options, - fillExtraContextMenuActions: (actions, e) => { - options.fillExtraContextMenuActions(actions, e); - this.fillContextMenuActions(actions, e); - } - }, part, paneCompositePart, instantiationService, storageService, extensionService, viewDescriptorService, viewService, contextKeyService, environmentService, layoutService); + super(location, + { + ...options, + fillExtraContextMenuActions: (actions, e) => { + options.fillExtraContextMenuActions(actions, e); + this.fillContextMenuActions(actions, e); + } + }, part, paneCompositePart, instantiationService, storageService, extensionService, viewDescriptorService, viewService, contextKeyService, environmentService, layoutService); if (showGlobalActivities) { this.globalCompositeBar = this._register(instantiationService.createInstance(GlobalCompositeBar, () => this.getContextMenuActions(), (theme: IColorTheme) => this.options.colors(theme), this.options.activityHoverOptions)); @@ -386,7 +488,7 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { } if (this.globalCompositeBar) { if (this.options.orientation === ActionsOrientation.VERTICAL) { - height -= (this.globalCompositeBar.size() * ActivitybarPart.ACTION_HEIGHT); + height -= (this.globalCompositeBar.size() * this.options.overflowActionSize); } else { width -= this.globalCompositeBar.element.clientWidth; } @@ -397,11 +499,23 @@ export class ActivityBarCompositeBar extends PaneCompositeBar { getActivityBarContextMenuActions(): IAction[] { const activityBarPositionMenu = this.menuService.getMenuActions(MenuId.ActivityBarPositionMenu, this.contextKeyService, { shouldForwardArgs: true, renderShortTitle: true }); const positionActions = getContextMenuActions(activityBarPositionMenu).secondary; - const actions = [ - new SubmenuAction('workbench.action.panel.position', localize('activity bar position', "Activity Bar Position"), positionActions), - toAction({ id: ToggleSidebarPositionAction.ID, label: ToggleSidebarPositionAction.getLabel(this.layoutService), run: () => this.instantiationService.invokeFunction(accessor => new ToggleSidebarPositionAction().run(accessor)) }), + const actions: IAction[] = [ + new SubmenuAction('workbench.action.activityBar.position', localize('activity bar position', "Activity Bar Position"), positionActions), ]; + // Show size submenu only when activity bar is in default position + const activityBarPosition = this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION); + if (activityBarPosition === ActivityBarPosition.DEFAULT) { + const isCompact = this.configurationService.getValue(LayoutSettings.ACTIVITY_BAR_COMPACT) ?? false; + const sizeActions = [ + toAction({ id: 'workbench.action.activityBar.size.default', label: localize('activityBarSizeDefault', "Default"), checked: !isCompact, run: () => this.configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_COMPACT, false) }), + toAction({ id: 'workbench.action.activityBar.size.compact', label: localize('activityBarSizeCompact', "Compact"), checked: isCompact, run: () => this.configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_COMPACT, true) }), + ]; + actions.push(new SubmenuAction('workbench.action.activityBar.size', localize('activity bar size', "Activity Bar Size"), sizeActions)); + } + + actions.push(toAction({ id: ToggleSidebarPositionAction.ID, label: ToggleSidebarPositionAction.getLabel(this.layoutService), run: () => this.instantiationService.invokeFunction(accessor => new ToggleSidebarPositionAction().run(accessor)) })); + if (this.part === Parts.SIDEBAR_PART) { actions.push(toAction({ id: ToggleSidebarVisibilityAction.ID, label: ToggleSidebarVisibilityAction.LABEL, run: () => this.instantiationService.invokeFunction(accessor => new ToggleSidebarVisibilityAction().run(accessor)) })); } @@ -427,7 +541,7 @@ registerAction2(class extends Action2 { order: 1 }, { id: MenuId.CommandPalette, - when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.DEFAULT), + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.DEFAULT), IsSessionsWindowContext.negate()), }] }); } @@ -453,7 +567,7 @@ registerAction2(class extends Action2 { order: 2 }, { id: MenuId.CommandPalette, - when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), IsSessionsWindowContext.negate()), }] }); } @@ -479,7 +593,7 @@ registerAction2(class extends Action2 { order: 3 }, { id: MenuId.CommandPalette, - when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.BOTTOM), + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.BOTTOM), IsSessionsWindowContext.negate()), }] }); } @@ -505,7 +619,7 @@ registerAction2(class extends Action2 { order: 4 }, { id: MenuId.CommandPalette, - when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.HIDDEN), + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.HIDDEN), IsSessionsWindowContext.negate()), }] }); } @@ -519,7 +633,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { submenu: MenuId.ActivityBarPositionMenu, title: localize('positionActivituBar', "Activity Bar Position"), group: '3_workbench_layout_move', - order: 2 + order: 2, + when: IsSessionsWindowContext.negate() }); MenuRegistry.appendMenuItem(MenuId.ViewContainerTitleContext, { diff --git a/vscode-web/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/vscode-web/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 78a3559db..4e8f0c754 100644 --- a/vscode-web/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/vscode-web/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -7,6 +7,7 @@ .monaco-workbench .part.titlebar { display: flex; flex-direction: row; + box-shadow: var(--vscode-shadow-md); } .monaco-workbench.mac .part.titlebar { @@ -146,6 +147,10 @@ visibility: hidden; } +.monaco-workbench .part.titlebar.inactive > * { + opacity: 0.6; +} + .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item > .action-label, .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center > .monaco-toolbar > .monaco-action-bar > .actions-container > .action-item.monaco-dropdown-with-primary .action-label { color: var(--vscode-titleBar-activeForeground); @@ -168,7 +173,7 @@ border: 1px solid var(--vscode-commandCenter-border); overflow: hidden; margin: 0 6px; - border-radius: 4px; + border-radius: var(--vscode-cornerRadius-medium); height: 22px; width: 38vw; max-width: 600px; @@ -198,6 +203,25 @@ text-overflow: ellipsis; } +/* Compact mode: left-aligned label, no icon, full width */ +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center .action-item.command-center-center .action-item.command-center-quick-pick.compact-mode { + margin: auto auto auto 0; + padding-left: 8px; + flex: 1; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center .action-item.command-center-center:has(.compact-mode) > .monaco-toolbar > .monaco-action-bar > .actions-container { + margin: 0; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center .action-item.command-center-center:has(.compact-mode) > .monaco-toolbar { + flex: 1; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center .action-item.command-center-center:has(.compact-mode) > .monaco-toolbar > .monaco-action-bar { + width: 100%; +} + .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-center > .window-title > .command-center .action-item.command-center-center.multiple { justify-content: flex-start; padding: 0 12px; @@ -373,6 +397,22 @@ color: white; } +/* Center-Adjacent Toolbar (e.g., update indicator) */ +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .center-adjacent-toolbar-container { + z-index: 2500; + -webkit-app-region: no-drag; + margin-right: auto; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .center-adjacent-toolbar-container.has-no-actions { + display: none; +} + +/* Hidden when the title bar is too narrow to fit it without pushing the window controls off-screen (#303222). */ +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .center-adjacent-toolbar-container.overflowing { + display: none; +} + /* Action Tool Bar Controls */ .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .action-toolbar-container { display: none; diff --git a/vscode-web/src/vs/workbench/browser/web.main.ts b/vscode-web/src/vs/workbench/browser/web.main.ts index 31c77e4de..6ed7b9160 100644 --- a/vscode-web/src/vs/workbench/browser/web.main.ts +++ b/vscode-web/src/vs/workbench/browser/web.main.ts @@ -5,7 +5,6 @@ import { mark } from '../../base/common/performance.js'; import { domContentLoaded, detectFullscreen, getCookieValue, getWindow } from '../../base/browser/dom.js'; -import { assertReturnsDefined } from '../../base/common/types.js'; import { ServiceCollection } from '../../platform/instantiation/common/serviceCollection.js'; import { ILogService, ConsoleLogger, getLogLevel, ILoggerService, ILogger } from '../../platform/log/common/log.js'; import { ConsoleLogInAutomationLogger } from '../../platform/log/browser/log.js'; @@ -25,7 +24,7 @@ import { FileService } from '../../platform/files/common/fileService.js'; import { Schemas, connectionTokenCookieName } from '../../base/common/network.js'; import { IAnyWorkspaceIdentifier, IWorkspaceContextService, UNKNOWN_EMPTY_WINDOW_WORKSPACE, isTemporaryWorkspace, isWorkspaceIdentifier } from '../../platform/workspace/common/workspace.js'; import { IWorkbenchConfigurationService } from '../services/configuration/common/configuration.js'; -import { onUnexpectedError } from '../../base/common/errors.js'; +import { onUnexpectedError, ErrorNoTelemetry } from '../../base/common/errors.js'; import { setFullscreen } from '../../base/browser/browser.js'; import { URI, UriComponents } from '../../base/common/uri.js'; import { WorkspaceService } from '../services/configuration/browser/configurationService.js'; @@ -37,7 +36,7 @@ import { BrowserStorageService } from '../services/storage/browser/storageServic import { IStorageService } from '../../platform/storage/common/storage.js'; import { toLocalISOString } from '../../base/common/date.js'; import { isWorkspaceToOpen, isFolderToOpen } from '../../platform/window/common/window.js'; -import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from '../services/workspaces/browser/workspaces.js'; +import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from '../../platform/workspaces/common/workspaceIdentifier.js'; import { InMemoryFileSystemProvider } from '../../platform/files/common/inMemoryFilesystemProvider.js'; import { ICommandService } from '../../platform/commands/common/commands.js'; import { IndexedDBFileSystemProvider } from '../../platform/files/browser/indexedDBFileSystemProvider.js'; @@ -46,7 +45,8 @@ import { IRequestService } from '../../platform/request/common/request.js'; import { IUserDataInitializationService, IUserDataInitializer, UserDataInitializationService } from '../services/userData/browser/userDataInit.js'; import { UserDataSyncStoreManagementService } from '../../platform/userDataSync/common/userDataSyncStoreService.js'; import { IUserDataSyncStoreManagementService } from '../../platform/userDataSync/common/userDataSync.js'; -import { ILifecycleService } from '../services/lifecycle/common/lifecycle.js'; +import { ILifecycleService, WillShutdownEvent } from '../services/lifecycle/common/lifecycle.js'; +import { Event } from '../../base/common/event.js'; import { Action2, MenuId, registerAction2 } from '../../platform/actions/common/actions.js'; import { IInstantiationService, ServicesAccessor } from '../../platform/instantiation/common/instantiation.js'; import { localize, localize2 } from '../../nls.js'; @@ -97,9 +97,13 @@ import { mainWindow } from '../../base/browser/window.js'; import { INotificationService, Severity } from '../../platform/notification/common/notification.js'; import { IDefaultAccountService } from '../../platform/defaultAccount/common/defaultAccount.js'; import { DefaultAccountService } from '../services/accounts/browser/defaultAccount.js'; -import { AccountPolicyService } from '../services/policies/common/accountPolicyService.js'; -import { WorkbenchModeService } from '../services/layout/browser/workbenchModeService.js'; -import { IWorkbenchModeService } from '../services/layout/common/workbenchModeService.js'; +import { AccountPolicyService, IAccountPolicyGateService } from '../services/policies/common/accountPolicyService.js'; + +export interface IBrowserMainWorkbench { + startup(): IInstantiationService; + readonly onWillShutdown: Event; + readonly onDidShutdown: Event; +} export class BrowserMain extends Disposable { @@ -127,7 +131,7 @@ export class BrowserMain extends Disposable { const [services] = await Promise.all([this.initServices(), domContentLoaded(getWindow(this.domElement))]); // Create Workbench - const workbench = new Workbench(this.domElement, undefined, services.serviceCollection, services.logService); + const workbench = this.createWorkbench(this.domElement, services.serviceCollection, services.logService); // Listeners this.registerListeners(workbench); @@ -214,7 +218,7 @@ export class BrowserMain extends Disposable { await remoteAuthorityResolverService.resolveAuthority(this.configuration.remoteAuthority); }, openTunnel: async tunnelOptions => { - const tunnel = assertReturnsDefined(await remoteExplorerService.forward({ + const tunnel = await remoteExplorerService.forward({ remote: tunnelOptions.remoteAddress, local: tunnelOptions.localAddressPort, name: tunnelOptions.label, @@ -230,7 +234,11 @@ export class BrowserMain extends Disposable { onAutoForward: undefined, requireLocalPort: undefined, protocol: tunnelOptions.protocol === TunnelProtocol.Https ? tunnelOptions.protocol : TunnelProtocol.Http - })); + }); + + if (tunnel === undefined) { + throw new ErrorNoTelemetry(`Could not open tunnel to ${tunnelOptions.remoteAddress.host}:${tunnelOptions.remoteAddress.port}.`); + } if (typeof tunnel === 'string') { throw new Error(tunnel); @@ -249,7 +257,11 @@ export class BrowserMain extends Disposable { }); } - private registerListeners(workbench: Workbench): void { + protected createWorkbench(domElement: HTMLElement, serviceCollection: ServiceCollection, logService: ILogService): IBrowserMainWorkbench { + return new Workbench(domElement, undefined, serviceCollection, logService); + } + + private registerListeners(workbench: IBrowserMainWorkbench): void { // Workbench Lifecycle this._register(workbench.onWillShutdown(() => this.onWillShutdownDisposables.clear())); @@ -351,34 +363,35 @@ export class BrowserMain extends Disposable { this._register(RemoteFileSystemProviderClient.register(remoteAgentService, fileService, logService)); // Default Account - const defaultAccountService = this._register(new DefaultAccountService()); + const defaultAccountService = this._register(new DefaultAccountService(productService)); serviceCollection.set(IDefaultAccountService, defaultAccountService); // Policies const policyService = new AccountPolicyService(logService, defaultAccountService); serviceCollection.set(IPolicyService, policyService); + serviceCollection.set(IAccountPolicyGateService, policyService); - // Long running services (workspace, config, storage) - const [configurationService, storageService] = await Promise.all([ - this.createWorkspaceService(workspace, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, uriIdentityService, policyService, logService).then(service => { - - // Workspace - serviceCollection.set(IWorkspaceContextService, service); - - // Configuration - serviceCollection.set(IWorkbenchConfigurationService, service); - - return service; - }), - - this.createStorageService(workspace, logService, userDataProfileService).then(service => { + const configurationService = await this.createWorkspaceAndDependentServices(serviceCollection, workspace, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, uriIdentityService, policyService, logService, loggerService, remoteAuthorityResolverService, productService); - // Storage - serviceCollection.set(IStorageService, service); + return { serviceCollection, configurationService, logService }; + } - return service; - }) - ]); + private async createWorkspaceAndDependentServices( + serviceCollection: ServiceCollection, + workspace: IAnyWorkspaceIdentifier, + environmentService: IBrowserWorkbenchEnvironmentService, + userDataProfileService: IUserDataProfileService, + userDataProfilesService: BrowserUserDataProfilesService, + fileService: FileService, + remoteAgentService: IRemoteAgentService, + uriIdentityService: IUriIdentityService, + policyService: IPolicyService, + logService: ILogService, + loggerService: ILoggerService, + remoteAuthorityResolverService: IRemoteAuthorityResolverService, + productService: IProductService, + ): Promise { + const { configurationService, storageService } = await this.createWorkspaceConfigAndStorageServices(serviceCollection, workspace, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, uriIdentityService, policyService, logService, remoteAuthorityResolverService); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // @@ -389,26 +402,6 @@ export class BrowserMain extends Disposable { // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // Layout Mode - const workbenchModeService: WorkbenchModeService = this._register(new WorkbenchModeService(configurationService, fileService, environmentService, uriIdentityService, logService, storageService)); - serviceCollection.set(IWorkbenchModeService, workbenchModeService); - try { - await workbenchModeService.initialize(); - } catch (error) { - logService.error('Error while initializing workbench mode service', error); - } - - // Workspace Trust Service - const workspaceTrustEnablementService = new WorkspaceTrustEnablementService(configurationService, environmentService); - serviceCollection.set(IWorkspaceTrustEnablementService, workspaceTrustEnablementService); - - const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, remoteAuthorityResolverService, storageService, uriIdentityService, environmentService, configurationService, workspaceTrustEnablementService, fileService); - serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService); - - // Update workspace trust so that configuration is updated accordingly - configurationService.updateWorkspaceTrust(workspaceTrustManagementService.isWorkspaceTrusted()); - this._register(workspaceTrustManagementService.onDidChangeTrust(() => configurationService.updateWorkspaceTrust(workspaceTrustManagementService.isWorkspaceTrusted()))); - // Request Service const requestService = new BrowserRequestService(remoteAgentService, configurationService, loggerService); serviceCollection.set(IRequestService, requestService); @@ -435,7 +428,7 @@ export class BrowserMain extends Disposable { // Userdata Initialize Service const userDataInitializers: IUserDataInitializer[] = []; userDataInitializers.push(new UserDataSyncInitializer(environmentService, secretStorageService, userDataSyncStoreManagementService, fileService, userDataProfilesService, storageService, productService, requestService, logService, uriIdentityService)); - if (environmentService.options.profile) { + if (environmentService.options?.profile) { userDataInitializers.push(new UserDataProfileInitializer(environmentService, fileService, userDataProfileService, storageService, logService, uriIdentityService, requestService)); } const userDataInitializationService = new UserDataInitializationService(userDataInitializers); @@ -451,10 +444,55 @@ export class BrowserMain extends Disposable { logService.error(error); } - return { serviceCollection, configurationService, logService }; + return configurationService; + } + + /** + * Creates and registers the workspace context, configuration, storage, + * and workspace trust services. Override this to provide different + * workspace/configuration implementations (e.g., sessions in-memory + * workspace). Overrides must also register workspace trust services. + */ + protected async createWorkspaceConfigAndStorageServices( + serviceCollection: ServiceCollection, + workspace: IAnyWorkspaceIdentifier, + environmentService: IBrowserWorkbenchEnvironmentService, + userDataProfileService: IUserDataProfileService, + userDataProfilesService: BrowserUserDataProfilesService, + fileService: FileService, + remoteAgentService: IRemoteAgentService, + uriIdentityService: IUriIdentityService, + policyService: IPolicyService, + logService: ILogService, + remoteAuthorityResolverService: IRemoteAuthorityResolverService, + ): Promise<{ configurationService: IWorkbenchConfigurationService; storageService: IStorageService }> { + const [configurationService, storageService] = await Promise.all([ + this.createWorkspaceService(workspace, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, uriIdentityService, policyService, logService).then(service => { + serviceCollection.set(IWorkspaceContextService, service); + serviceCollection.set(IWorkbenchConfigurationService, service); + return service; + }), + this.createStorageService(workspace, logService, userDataProfileService).then(service => { + serviceCollection.set(IStorageService, service); + return service; + }) + ]); + + // Workspace Trust Service + const workspaceTrustEnablementService = new WorkspaceTrustEnablementService(configurationService, environmentService); + serviceCollection.set(IWorkspaceTrustEnablementService, workspaceTrustEnablementService); + + const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, remoteAuthorityResolverService, storageService, uriIdentityService, environmentService, configurationService, workspaceTrustEnablementService, fileService); + serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService); + + // Update workspace trust so that configuration is updated accordingly + configurationService.updateWorkspaceTrust(workspaceTrustManagementService.isWorkspaceTrusted()); + this._register(workspaceTrustManagementService.onDidChangeTrust(() => configurationService.updateWorkspaceTrust(workspaceTrustManagementService.isWorkspaceTrusted()))); + + return { configurationService, storageService }; } - private async initializeUserData(userDataInitializationService: UserDataInitializationService, configurationService: WorkspaceService) { + private async initializeUserData(userDataInitializationService: UserDataInitializationService, configurationService: IWorkbenchConfigurationService) { if (await userDataInitializationService.requiresInitialization()) { mark('code/willInitRequiredUserData'); @@ -463,7 +501,9 @@ export class BrowserMain extends Disposable { // Important: Reload only local user configuration after initializing // Reloading complete configuration blocks workbench until remote configuration is loaded. - await configurationService.reloadLocalUserConfiguration(); + if (configurationService instanceof WorkspaceService) { + await configurationService.reloadLocalUserConfiguration(); + } mark('code/didInitRequiredUserData'); } @@ -554,7 +594,7 @@ export class BrowserMain extends Disposable { })); } - private async createStorageService(workspace: IAnyWorkspaceIdentifier, logService: ILogService, userDataProfileService: IUserDataProfileService): Promise { + protected async createStorageService(workspace: IAnyWorkspaceIdentifier, logService: ILogService, userDataProfileService: IUserDataProfileService): Promise { const storageService = new BrowserStorageService(workspace, userDataProfileService, logService); try { @@ -635,6 +675,7 @@ export class BrowserMain extends Disposable { return id ? { ...identifier, id } : identifier; } + // Empty window workspace return id ? { id } : UNKNOWN_EMPTY_WINDOW_WORKSPACE; /* above codes are changed by github1s */ } diff --git a/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html b/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html deleted file mode 100644 index 8c0ea0e6a..000000000 --- a/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html +++ /dev/null @@ -1,1246 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index.html b/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index.html index 10efd81c3..a86821405 100644 --- a/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/vscode-web/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -53,9 +53,6 @@ perfMark('scriptStart'); - /** @type {MessageChannel | undefined} */ - let outerIframeMessageChannel; - /** * Use polling to track focus of main webview and iframes within the webview * @@ -257,66 +254,31 @@ return reject(new Error('Service Workers are not enabled. Webviews will not work. Try disabling private/incognito mode.')); } - const swPath = encodeURI(`service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`); - navigator.serviceWorker.register(swPath, { type: 'module' }) + const swPath = encodeURI(`service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}&platform=${searchParams.get('platform')}`); + navigator.serviceWorker.register(swPath, { type: 'module', updateViaCache: 'none' }) .then(async registration => { - /** - * @param {MessageEvent} event - */ - const versionHandler = async (event) => { - if (event.data.channel !== 'version') { - return; - } - - navigator.serviceWorker.removeEventListener('message', versionHandler); - if (event.data.version === expectedWorkerVersion) { - return resolve(); - } else { - console.log(`Found unexpected service worker version. Found: ${event.data.version}. Expected: ${expectedWorkerVersion}`); - console.log(`Attempting to reload service worker`); - - // If we have the wrong version, try once (and only once) to unregister and re-register - // Note that `.update` doesn't seem to work desktop electron at the moment so we use - // `unregister` and `register` here. - return registration.unregister() - .then(() => navigator.serviceWorker.register(swPath)) - .finally(() => { resolve(); }); - } - }; - navigator.serviceWorker.addEventListener('message', versionHandler); - - const postVersionMessage = (/** @type {ServiceWorker} */ controller) => { - outerIframeMessageChannel = new MessageChannel(); - controller.postMessage({ channel: 'version' }, [outerIframeMessageChannel.port2]); - }; - - // At this point, either the service worker is ready and - // became our controller, or we need to wait for it. - // Note that navigator.serviceWorker.controller could be a - // controller from a previously loaded service worker. - const currentController = navigator.serviceWorker.controller; - if (currentController?.scriptURL.endsWith(swPath)) { - // service worker already loaded & ready to receive messages - postVersionMessage(currentController); - } else { - if (currentController) { - console.log(`Found unexpected service worker controller. Found: ${currentController.scriptURL}. Expected: ${swPath}. Waiting for controllerchange.`); - } else { - console.log(`No service worker controller found. Waiting for controllerchange.`); - } + if (navigator.serviceWorker.controller) { + // A previous SW is already controlling. Force an update + // check so we don't serve stale resources after a VS Code + // update. register() resolves before the update check + // completes, so we must call update() explicitly to wait + // for the download + byte-comparison to finish. + registration = await registration.update(); + } - // Either there's no controlling service worker, or it's an old one. - // Wait for it to change before posting the message - const onControllerChange = () => { - navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange); - if (navigator.serviceWorker.controller) { - postVersionMessage(navigator.serviceWorker.controller); - } else { - return reject(new Error('No controller found.')); - } - }; - navigator.serviceWorker.addEventListener('controllerchange', onControllerChange); + // If a new worker was found, wait for it to take control via skipWaiting() + clients.claim() in the SW. + if ( + // New worker + registration.installing || registration.waiting + // First ever load + || !navigator.serviceWorker.controller + ) { + await new Promise(r => { + navigator.serviceWorker.addEventListener('controllerchange', r, { once: true }); + }); } + + return resolve(); }).catch(error => { if (!onElectron && error instanceof Error && error.message.includes('user denied permission')) { return reject(new Error(`Could not register service worker. Please make sure third party cookies are enabled: ${error}`)); @@ -364,6 +326,7 @@ async signalReady() { /* below codes are changed by github1s */ + perfMark('signalingReady'); const parentOrigin = searchParams.get('parentOrigin') || ''; window.parent.postMessage({ target: ID, channel: 'webview-ready', data: {} }, parentOrigin, [this.channel.port2]); /* above codes are changed by github1s */ @@ -456,11 +419,21 @@ if (!disableServiceWorker) { hostMessaging.onMessage('did-load-resource', (_event, data) => { - assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-resource', data }, data.data?.buffer ? [data.data.buffer] : []); + const transfer = data.stream ? [data.stream] : []; + assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-resource', data }, transfer); }); - hostMessaging.onMessage('did-load-localhost', (_event, data) => { - assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-localhost', data }); + for (const channel of [ + 'did-load-resource-end', + 'did-load-localhost', + ]) { + hostMessaging.onMessage(channel, (_event, data) => { + assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel, data }); + }); + } + + hostMessaging.onMessage('did-load-resource-chunk', (_event, data) => { + assertIsDefined(navigator.serviceWorker.controller).postMessage({ channel: 'did-load-resource-chunk', data }, data.data?.buffer ? [data.data.buffer] : []); }); navigator.serviceWorker.addEventListener('message', event => { @@ -531,7 +504,7 @@ * @param {MouseEvent} event */ const handleInnerClick = (event) => { - if (!event?.view?.document) { + if (!event.isTrusted || !event?.view?.document) { return; } @@ -604,7 +577,8 @@ e.preventDefault(); } - hostMessaging.postMessage('did-keydown', { + /** @type {import('../webviewMessages').FromWebviewMessage['did-keydown']} */ + const data = { key: e.key, keyCode: e.keyCode, code: e.code, @@ -612,14 +586,17 @@ altKey: e.altKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, - repeat: e.repeat - }); + repeat: e.repeat, + isTrusted: e.isTrusted + }; + hostMessaging.postMessage('did-keydown', data); }; /** * @param {KeyboardEvent} e */ const handleInnerKeyup = (e) => { - hostMessaging.postMessage('did-keyup', { + /** @type {import('../webviewMessages').FromWebviewMessage['did-keyup']} */ + const data = { key: e.key, keyCode: e.keyCode, code: e.code, @@ -627,8 +604,10 @@ altKey: e.altKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, - repeat: e.repeat - }); + repeat: e.repeat, + isTrusted: e.isTrusted + }; + hostMessaging.postMessage('did-keyup', data); }; /** @@ -1216,16 +1195,6 @@ unloadMonitor.onIframeLoaded(newFrame); } - if (!disableServiceWorker && outerIframeMessageChannel) { - outerIframeMessageChannel.port1.onmessage = event => { - switch (event.data.channel) { - case 'load-resource': - case 'load-localhost': - hostMessaging.postMessage(event.data.channel, event.data); - return; - } - }; - } }); // propagate vscode-context-menu-visible class diff --git a/vscode-web/src/vs/workbench/services/label/common/labelService.ts b/vscode-web/src/vs/workbench/services/label/common/labelService.ts index f2d0971a7..2557d4b4f 100644 --- a/vscode-web/src/vs/workbench/services/label/common/labelService.ts +++ b/vscode-web/src/vs/workbench/services/label/common/labelService.ts @@ -135,7 +135,7 @@ export class LabelService extends Disposable implements ILabelService { private formatters: ResourceLabelFormatter[]; - private readonly _onDidChangeFormatters = this._register(new Emitter({ leakWarningThreshold: 400 })); + private readonly _onDidChangeFormatters = this._register(new Emitter({ leakWarningThreshold: 400, leakWarningName: 'LabelService._onDidChangeFormatters' })); readonly onDidChangeFormatters = this._onDidChangeFormatters.event; private readonly storedFormattersMemento: Memento; @@ -314,10 +314,6 @@ export class LabelService extends Disposable implements ILabelService { /* above codes are changed by github1s */ if (isWorkspace(workspace)) { - if (workspace.isAgentSessionsWorkspace) { - return localize('agentSessionsWorkspace', "Agent Sessions"); - } - const identifier = toWorkspaceIdentifier(workspace); if (isSingleFolderWorkspaceIdentifier(identifier) || isWorkspaceIdentifier(identifier)) { return this.getWorkspaceLabel(identifier, options); @@ -464,10 +460,23 @@ export class LabelService extends Disposable implements ILabelService { const i = resource.authority.indexOf('+'); return i === -1 ? resource.authority : resource.authority.slice(i + 1); } - case 'path': + case 'path': { + let pathValue = resource.path; + if (formatting.stripPathSegments) { + let pos = 0; + for (let i = 0; i < formatting.stripPathSegments; i++) { + const next = pathValue.indexOf('/', pos + 1); + if (next === -1) { + break; + } + pos = next; + } + pathValue = pathValue.substring(pos); + } return formatting.stripPathStartingSeparator - ? resource.path.slice(resource.path[0] === formatting.separator ? 1 : 0) - : resource.path; + ? pathValue.slice(pathValue[0] === formatting.separator ? 1 : 0) + : pathValue; + } default: { if (qsToken === 'query') { const { query } = resource;