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;