diff --git a/extensions/github1s/yarn.lock b/extensions/github1s/yarn.lock index 118e60dcd..5b860cf48 100644 --- a/extensions/github1s/yarn.lock +++ b/extensions/github1s/yarn.lock @@ -426,11 +426,16 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.1: +bn.js@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -474,7 +479,7 @@ browserify-des@^1.0.0: inherits "^2.0.1" safe-buffer "^5.1.2" -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== @@ -483,19 +488,19 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: randombytes "^2.0.1" browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + version "4.2.2" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e" + integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg== dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" + bn.js "^5.2.1" + browserify-rsa "^4.1.0" create-hash "^1.2.0" create-hmac "^1.1.7" - elliptic "^6.5.3" + elliptic "^6.5.4" inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" + parse-asn1 "^5.1.6" + readable-stream "^3.6.2" + safe-buffer "^5.2.1" browserify-zlib@^0.2.0: version "0.2.0" @@ -725,7 +730,7 @@ electron-to-chromium@^1.4.118: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f" integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA== -elliptic@^6.5.3: +elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -1512,7 +1517,7 @@ pako@~1.0.5: resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -parse-asn1@^5.0.0, parse-asn1@^5.1.5: +parse-asn1@^5.0.0, parse-asn1@^5.1.6: version "5.1.6" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== @@ -1656,6 +1661,15 @@ readable-stream@^3.5.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + rechoir@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" @@ -1711,7 +1725,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== diff --git a/package.json b/package.json index 8bec2aa4b..db8e350ed 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "lib": "lib" }, "devDependencies": { - "@github1s/vscode-web": "0.14.0", + "@github1s/vscode-web": "0.15.0", "@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/parser": "^5.40.1", "chokidar": "^3.5.3", diff --git a/tests/__tests__/index.test.ts b/tests/__tests__/index.test.ts index 522ad8721..b299e9653 100644 --- a/tests/__tests__/index.test.ts +++ b/tests/__tests__/index.test.ts @@ -43,7 +43,7 @@ it('should load successfully', async () => { // Make sure the repo loads await page.click('div[role="tab"]'); // GitHub repo Link available - await page.$eval('div.home-bar[role="toolbar"]', (el) => el.innerHTML); + await page.$eval('div.home-bar', (el) => el.innerHTML); // File explorer available await page.$eval('div[role="tree"][aria-label="Files Explorer"]', (el) => el.innerHTML); const tab = await page.$eval('div[role="tab"] .label-name', (el: HTMLElement) => el.innerText); diff --git a/vscode-web/.VERSION b/vscode-web/.VERSION index d860c4721..2726943bf 100644 --- a/vscode-web/.VERSION +++ b/vscode-web/.VERSION @@ -1 +1 @@ -1.83.1 \ No newline at end of file +1.84.2 \ No newline at end of file diff --git a/vscode-web/package.json b/vscode-web/package.json index e020d244e..25875ebdb 100644 --- a/vscode-web/package.json +++ b/vscode-web/package.json @@ -1,6 +1,6 @@ { "name": "@github1s/vscode-web", - "version": "0.14.0", + "version": "0.15.0", "description": "VS Code web for GitHub1s", "author": "github1s", "license": "MIT", @@ -34,13 +34,13 @@ "tas-client-umd": "0.1.8", "vscode-oniguruma": "1.7.0", "vscode-textmate": "9.0.0", - "xterm": "5.2.0-beta.30", - "xterm-addon-canvas": "0.5.0-beta.22", - "xterm-addon-image": "0.6.0-beta.14", - "xterm-addon-search": "0.13.0-beta.20", - "xterm-addon-serialize": "0.11.0-beta.20", - "xterm-addon-unicode11": "0.6.0-beta.12", - "xterm-addon-webgl": "0.16.0-beta.30" + "xterm": "5.4.0-beta.32", + "xterm-addon-canvas": "0.6.0-beta.32", + "xterm-addon-image": "0.6.0-beta.21", + "xterm-addon-search": "0.14.0-beta.31", + "xterm-addon-serialize": "0.12.0-beta.31", + "xterm-addon-unicode11": "0.7.0-beta.31", + "xterm-addon-webgl": "0.17.0-beta.31" }, "devDependencies": { "@types/trusted-types": "^2.0.0", diff --git a/vscode-web/scripts/.patch b/vscode-web/scripts/.patch index 01178c81d..eb4ba1abc 100644 --- a/vscode-web/scripts/.patch +++ b/vscode-web/scripts/.patch @@ -1,14 +1,14 @@ { "vs/code/browser/workbench/workbench.ts": "a954327b52b6ed462b3b7fbd2301c6ba11bf135ca7ba70c5f552214309492946", - "vs/editor/common/config/editorOptions.ts": "611f03be53deb2d1326e31b618da729a5c2660d647149e1452792dcfc63c1b64", - "vs/workbench/browser/parts/activitybar/activitybarActions.ts": "6f7e46ab77834e26c0cd6ef4bd31e0fb54d605b677d8e1746522e22ceebae1e5", - "vs/workbench/browser/parts/activitybar/activitybarPart.ts": "101b6d4d65a1efb478caf77159684f691f3075ec52c5cd35cef1fee521d4edac", - "vs/workbench/browser/parts/titlebar/media/titlebarpart.css": "26bf68e6e1b3acfcac13405eba2d2b54ce4771ede2e75e5788beb9e5fe5da569", - "vs/workbench/browser/web.main.ts": "3f41a99e744b80d161af5f9830b3394e4953d91ed38d282179e0f4bcc385c205", + "vs/editor/common/config/editorOptions.ts": "043c420c18f97c42b9fa45a0f12b10ab81f464a3d3293d177dfbf4d63e4693be", + "vs/workbench/browser/parts/activitybar/activitybarPart.ts": "7396307c8bcf88eb7b306fbe5c3648a4eeb7fe817de4f508ed6ce256d3aab9ea", + "vs/workbench/browser/parts/titlebar/media/titlebarpart.css": "12ee25ef0c98f63a6f3dbc3d78c648408db81c165aa547d8c7dcfe89c5d25e8c", + "vs/workbench/browser/web.main.ts": "6fe9eeb0cdebd7e95fcb7da48524aded5b544b41a31752486e8351cd505ab9f5", "vs/workbench/contrib/files/browser/editors/fileEditorInput.ts": "27714e54f72edb805459d991c607d2867bd791e46d4c58eb4ab1a418f767e817", "vs/workbench/contrib/webview/browser/pre/index.html": "6dc11aefde8587732dba85116dac2718cef9287075c8d3a306663a7741e6910f", "vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts": "3cc4c831bcffc9b2837890d64c651ba5508af9e9693d6d2cf425305ff27cba9f", "vs/workbench/services/label/common/labelService.ts": "73237cce0f9496151ea8ae5079676bbdfa15ce49de9b05621d39fcd04e9c1f0d", - "vs/workbench/services/textfile/browser/textFileService.ts": "514ae0a7922c9e0e63c1b50ef08936d0b900e4970c19ba219b73759d62bac1a4", - "vs/workbench/services/editor/browser/editorResolverService.ts": "43cd774a4715e98afaf85b3d44f0381d0b83dc1b9cd75fc090553f84fa0f7e80" + "vs/workbench/services/textfile/browser/textFileService.ts": "193176bfccbbeae7fdf7b546992647554503dc4df8579db7094a4eee3cf50451", + "vs/workbench/services/editor/browser/editorResolverService.ts": "43cd774a4715e98afaf85b3d44f0381d0b83dc1b9cd75fc090553f84fa0f7e80", + "vs/workbench/browser/parts/globalCompositeBar.ts": "d3ae76e7831976c34be6b9bf07eb87b05eb46d45eb7ebff039169a8f5372ff87" } \ No newline at end of file diff --git a/vscode-web/src/vs/editor/common/config/editorOptions.ts b/vscode-web/src/vs/editor/common/config/editorOptions.ts index 0db5caa2f..354c15a92 100644 --- a/vscode-web/src/vs/editor/common/config/editorOptions.ts +++ b/vscode-web/src/vs/editor/common/config/editorOptions.ts @@ -562,6 +562,11 @@ export interface IEditorOptions { * Defaults to true. */ occurrencesHighlight?: boolean; + /** + * Enable semantic occurrences highlight. + * Defaults to true. + */ + multiDocumentOccurrencesHighlight?: boolean; /** * Show code lens * Defaults to true. @@ -1305,9 +1310,9 @@ class EditorAccessibilitySupport extends BaseEditorOption()); private content: HTMLElement | undefined; - // below codes are changed by github1s - private homeBarContainer: HTMLElement | undefined; - // above codes are changed by github1s - - private menuBar: CustomMenubarControl | undefined; - private menuBarContainer: HTMLElement | undefined; - - private compositeBar: CompositeBar; - private compositeBarContainer: HTMLElement | undefined; - - private globalActivityAction: ActivityAction | undefined; - private globalActivityActionBar: ActionBar | undefined; - private globalActivitiesContainer: HTMLElement | undefined; - private readonly globalActivity: ICompositeActivity[] = []; - - private accountsActivityAction: ActivityAction | undefined; - - private readonly accountsActivity: ICompositeActivity[] = []; - - private readonly compositeActions = new Map(); - private readonly viewContainerDisposables = new Map(); - - private readonly keyboardNavigationDisposables = this._register(new DisposableStore()); - - private readonly location = ViewContainerLocation.Sidebar; - private hasExtensionsRegistered: boolean = false; - - private readonly enabledViewContainersContextKeys: Map> = new Map>(); - constructor( private readonly paneCompositePart: IPaneCompositePart, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IThemeService themeService: IThemeService, - @IStorageService private readonly storageService: IStorageService, - @IExtensionService private readonly extensionService: IExtensionService, - @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, + @IStorageService storageService: IStorageService, ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); - - for (const cachedViewContainer of this.cachedViewContainers) { - cachedViewContainer.visible = !this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer); - } - this.compositeBar = this.createCompositeBar(); - - this.onDidRegisterViewContainers(this.getViewContainers()); - - this.registerListeners(); - } - private createCompositeBar() { - const cachedItems = this.cachedViewContainers - .map(container => ({ - id: container.id, - name: container.name, - visible: container.visible, - order: container.order, - pinned: container.pinned, - })); - - return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { - icon: true, + private createCompositeBar(): PaneCompositeBar { + return this.instantiationService.createInstance(ActivityBarCompositeBar, { + partContainerClass: 'activitybar', + pinnedViewContainersKey: ActivitybarPart.pinnedViewContainersKey, + placeholderViewContainersKey: ActivitybarPart.placeholderViewContainersKey, + viewContainersWorkspaceStateKey: ActivitybarPart.viewContainersWorkspaceStateKey, orientation: ActionsOrientation.VERTICAL, - activityHoverOptions: this.getActivityHoverOptions(), - preventLoopNavigation: true, - openComposite: async (compositeId, preserveFocus) => { - return (await this.paneCompositePart.openPaneComposite(compositeId, !preserveFocus)) ?? null; - }, - getActivityAction: compositeId => this.getCompositeActions(compositeId).activityAction, - getCompositePinnedAction: compositeId => this.getCompositeActions(compositeId).pinnedAction, - getCompositeBadgeAction: compositeId => this.getCompositeActions(compositeId).badgeAction, - getOnCompositeClickAction: compositeId => toAction({ id: compositeId, label: '', run: async () => this.paneCompositePart.getActivePaneComposite()?.getId() === compositeId ? this.paneCompositePart.hideActivePaneComposite() : this.paneCompositePart.openPaneComposite(compositeId) }), - fillExtraContextMenuActions: (actions, e?: MouseEvent | GestureEvent) => { - // Menu - const menuBarVisibility = getMenuBarVisibility(this.configurationService); - if (menuBarVisibility === 'compact' || menuBarVisibility === 'hidden' || menuBarVisibility === 'toggle') { - actions.unshift(...[toAction({ id: 'toggleMenuVisibility', label: localize('menu', "Menu"), checked: menuBarVisibility === 'compact', run: () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact') }), new Separator()]); - } - - if (menuBarVisibility === 'compact' && this.menuBarContainer && e?.target) { - if (isAncestor(e.target as Node, this.menuBarContainer)) { - actions.unshift(...[toAction({ id: 'hideCompactMenu', label: localize('hideMenu', "Hide Menu"), run: () => this.configurationService.updateValue('window.menuBarVisibility', 'toggle') }), new Separator()]); - } - } - - // Accounts - actions.push(new Separator()); - actions.push(toAction({ id: 'toggleAccountsVisibility', label: localize('accounts', "Accounts"), checked: this.accountsVisibilityPreference, run: () => this.accountsVisibilityPreference = !this.accountsVisibilityPreference })); - actions.push(new Separator()); - - // Toggle Sidebar - actions.push(toAction({ id: ToggleSidebarPositionAction.ID, label: ToggleSidebarPositionAction.getLabel(this.layoutService), run: () => this.instantiationService.invokeFunction(accessor => new ToggleSidebarPositionAction().run(accessor)) })); - - // Toggle Activity Bar - actions.push(toAction({ id: ToggleActivityBarVisibilityAction.ID, label: localize('hideActivitBar', "Hide Activity Bar"), run: () => this.instantiationService.invokeFunction(accessor => new ToggleActivityBarVisibilityAction().run(accessor)) })); + icon: true, + iconSize: 24, + activityHoverOptions: { + position: () => this.layoutService.getSideBarPosition() === Position.LEFT ? HoverPosition.RIGHT : HoverPosition.LEFT, }, - getContextMenuActionsForComposite: compositeId => this.getContextMenuActionsForComposite(compositeId), - getDefaultCompositeId: () => this.viewDescriptorService.getDefaultViewContainer(this.location)?.id, - hidePart: () => this.layoutService.setPartHidden(true, Parts.SIDEBAR_PART), - dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar, - async (id: string, focus?: boolean) => { return await this.paneCompositePart.openPaneComposite(id, focus) ?? null; }, - (from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore), - () => this.compositeBar.getCompositeBarItems(), - ), + preventLoopNavigation: true, + recomputeSizes: false, + fillExtraContextMenuActions: (actions, e?: MouseEvent | GestureEvent) => { }, compositeSize: 52, - colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme), - overflowActionSize: ActivitybarPart.ACTION_HEIGHT - })); - } - - private getActivityHoverOptions(): IActivityHoverOptions { - return { - position: () => this.layoutService.getSideBarPosition() === Position.LEFT ? HoverPosition.RIGHT : HoverPosition.LEFT, - }; + colors: (theme: IColorTheme) => ({ + activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), + inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), + activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER), + activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND), + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER), + activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined, + }), + overflowActionSize: ActivitybarPart.ACTION_HEIGHT, + }, Parts.ACTIVITYBAR_PART, this.paneCompositePart, true); } - private getContextMenuActionsForComposite(compositeId: string): IAction[] { - const actions: IAction[] = []; + protected override createContentArea(parent: HTMLElement): HTMLElement { + this.element = parent; + this.content = append(this.element, $('.content')); - const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!; - const defaultLocation = this.viewDescriptorService.getDefaultViewContainerLocation(viewContainer)!; - if (defaultLocation !== this.viewDescriptorService.getViewContainerLocation(viewContainer)) { - actions.push(toAction({ id: 'resetLocationAction', label: localize('resetLocation', "Reset Location"), run: () => this.viewDescriptorService.moveViewContainerToLocation(viewContainer, defaultLocation) })); - } else { - const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); - if (viewContainerModel.allViewDescriptors.length === 1) { - const viewToReset = viewContainerModel.allViewDescriptors[0]; - const defaultContainer = this.viewDescriptorService.getDefaultContainerById(viewToReset.id)!; - if (defaultContainer !== viewContainer) { - actions.push(toAction({ id: 'resetLocationAction', label: localize('resetLocation', "Reset Location"), run: () => this.viewDescriptorService.moveViewsToContainer([viewToReset], defaultContainer) })); - } - } + if (this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { + this.show(); } - return actions; + return this.content; } - private registerListeners(): void { + getPinnedPaneCompositeIds(): string[] { + return this.compositeBar.value?.getPinnedPaneCompositeIds() ?? []; + } - // View Container Changes - this._register(this.viewDescriptorService.onDidChangeViewContainers(({ added, removed }) => this.onDidChangeViewContainers(added, removed))); - this._register(this.viewDescriptorService.onDidChangeContainerLocation(({ viewContainer, from, to }) => this.onDidChangeViewContainerLocation(viewContainer, from, to))); + getVisiblePaneCompositeIds(): string[] { + return this.compositeBar.value?.getVisiblePaneCompositeIds() ?? []; + } - // View Container Visibility Changes - this.paneCompositePart.onDidPaneCompositeOpen(e => this.onDidChangeViewContainerVisibility(e.getId(), true)); - this.paneCompositePart.onDidPaneCompositeClose(e => this.onDidChangeViewContainerVisibility(e.getId(), false)); + focus(): void { + this.compositeBar.value?.focus(); + } - // Extension registration - const disposables = this._register(new DisposableStore()); - this._register(this.extensionService.onDidRegisterExtensions(() => { - disposables.clear(); - this.onDidRegisterExtensions(); - this.compositeBar.onDidChange(() => this.saveCachedViewContainers(), this, disposables); - this.storageService.onDidChangeValue(StorageScope.PROFILE, ActivitybarPart.PINNED_VIEW_CONTAINERS, disposables)(e => this.onDidPinnedViewContainersStorageValueChange(e), this, disposables); - this.storageService.onDidChangeValue(StorageScope.PROFILE, AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, disposables)(() => this.toggleAccountsActivity(), this, disposables); - })); + override updateStyles(): void { + super.updateStyles(); - // Register for configuration changes - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('window.menuBarVisibility')) { - if (getMenuBarVisibility(this.configurationService) === 'compact') { - this.installMenubar(); - } else { - this.uninstallMenubar(); - } - } - })); - } + const container = assertIsDefined(this.getContainer()); + const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; + container.style.backgroundColor = background; - private onDidChangeViewContainers(added: readonly { container: ViewContainer; location: ViewContainerLocation }[], removed: readonly { container: ViewContainer; location: ViewContainerLocation }[]) { - removed.filter(({ location }) => location === ViewContainerLocation.Sidebar).forEach(({ container }) => this.onDidDeregisterViewContainer(container)); - this.onDidRegisterViewContainers(added.filter(({ location }) => location === ViewContainerLocation.Sidebar).map(({ container }) => container)); + const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || ''; + container.classList.toggle('bordered', !!borderColor); + container.style.borderColor = borderColor ? borderColor : ''; } - private onDidChangeViewContainerLocation(container: ViewContainer, from: ViewContainerLocation, to: ViewContainerLocation) { - if (from === this.location) { - this.onDidDeregisterViewContainer(container); - } - - if (to === this.location) { - this.onDidRegisterViewContainers([container]); + show(): void { + if (!this.content) { + return; } - } - private onDidChangeViewContainerVisibility(id: string, visible: boolean) { - if (visible) { - // Activate view container action on opening of a view container - this.onDidViewContainerVisible(id); - } else { - // Deactivate view container action on close - this.compositeBar.deactivateComposite(id); + if (this.compositeBar.value) { + return; } - } - private onDidRegisterExtensions(): void { - this.hasExtensionsRegistered = true; + this.compositeBar.value = this.createCompositeBar(); + this.compositeBar.value.create(this.content); - // show/hide/remove composites - for (const { id } of this.cachedViewContainers) { - const viewContainer = this.getViewContainer(id); - if (viewContainer) { - this.showOrHideViewContainer(viewContainer); - } else { - if (this.viewDescriptorService.isViewContainerRemovedPermanently(id)) { - this.removeComposite(id); - } else { - this.hideComposite(id); - } - } + if (this.dimension) { + this.layout(this.dimension.width, this.dimension.height); } - - this.saveCachedViewContainers(); } - private onDidViewContainerVisible(id: string): void { - const viewContainer = this.getViewContainer(id); - if (viewContainer) { + hide(): void { + if (!this.compositeBar.value) { + return; + } - // Update the composite bar by adding - this.addComposite(viewContainer); - this.compositeBar.activateComposite(viewContainer.id); + this.compositeBar.clear(); - if (this.shouldBeHidden(viewContainer)) { - const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); - if (viewContainerModel.activeViewDescriptors.length === 0) { - // Update the composite bar by hiding - this.hideComposite(viewContainer.id); - } - } + if (this.content) { + clearNode(this.content); } } - showActivity(viewContainerOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable { - if (this.getViewContainer(viewContainerOrActionId)) { - return this.compositeBar.showActivity(viewContainerOrActionId, badge, clazz, priority); - } + override layout(width: number, height: number): void { + super.layout(width, height, 0, 0); - if (viewContainerOrActionId === GLOBAL_ACTIVITY_ID) { - return this.showGlobalActivity(GLOBAL_ACTIVITY_ID, badge, clazz, priority); + if (!this.compositeBar.value) { + return; } - if (viewContainerOrActionId === ACCOUNTS_ACTIVITY_ID) { - return this.showGlobalActivity(ACCOUNTS_ACTIVITY_ID, badge, clazz, priority); - } + // Layout contents + const contentAreaSize = super.layoutContents(width, height).contentSize; - return Disposable.None; + // Layout composite bar + this.compositeBar.value.layout(width, contentAreaSize.height); } - private showGlobalActivity(activityId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable { - if (typeof priority !== 'number') { - priority = 0; - } + toJSON(): object { + return { + type: Parts.ACTIVITYBAR_PART + }; + } +} - const activity: ICompositeActivity = { badge, clazz, priority }; - const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity; +export class ActivityBarCompositeBar extends PaneCompositeBar { - for (let i = 0; i <= activityCache.length; i++) { - if (i === activityCache.length) { - activityCache.push(activity); - break; - } else if (activityCache[i].priority <= priority) { - activityCache.splice(i, 0, activity); - break; - } - } - this.updateGlobalActivity(activityId); + private element: HTMLElement | undefined; - return toDisposable(() => this.removeGlobalActivity(activityId, activity)); - } + private menuBar: CustomMenubarControl | undefined; + private menuBarContainer: HTMLElement | undefined; + private compositeBarContainer: HTMLElement | undefined; + private readonly globalCompositeBar: GlobalCompositeBar | undefined; - private removeGlobalActivity(activityId: string, activity: ICompositeActivity): void { - const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity; - const index = activityCache.indexOf(activity); - if (index !== -1) { - activityCache.splice(index, 1); - this.updateGlobalActivity(activityId); - } - } + private readonly keyboardNavigationDisposables = this._register(new DisposableStore()); - private updateGlobalActivity(activityId: string): void { - const activityAction = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivityAction : this.accountsActivityAction; - if (!activityAction) { - return; + constructor( + options: IPaneCompositeBarOptions, + part: Parts, + paneCompositePart: IPaneCompositePart, + showGlobalActivities: boolean, + @IInstantiationService instantiationService: IInstantiationService, + @IStorageService storageService: IStorageService, + @IExtensionService extensionService: IExtensionService, + @IViewDescriptorService viewDescriptorService: IViewDescriptorService, + @IContextKeyService contextKeyService: IContextKeyService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @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, contextKeyService, environmentService, layoutService); + + if (showGlobalActivities) { + this.globalCompositeBar = this._register(instantiationService.createInstance(GlobalCompositeBar, () => this.getContextMenuActions(), (theme: IColorTheme) => this.options.colors(theme), this.options.activityHoverOptions)); } - const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity; - if (activityCache.length) { - const [{ badge, clazz, priority }] = activityCache; - if (badge instanceof NumberBadge && activityCache.length > 1) { - const cumulativeNumberBadge = this.getCumulativeNumberBadge(activityCache, priority); - activityAction.setBadge(cumulativeNumberBadge); - } else { - activityAction.setBadge(badge, clazz); + // Register for configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('window.menuBarVisibility')) { + if (getMenuBarVisibility(this.configurationService) === 'compact') { + this.installMenubar(); + } else { + this.uninstallMenubar(); + } } - } else { - activityAction.setBadge(undefined); - } + })); } - private getCumulativeNumberBadge(activityCache: ICompositeActivity[], priority: number): NumberBadge { - const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && activity.priority === priority); - const number = numberActivities.reduce((result, activity) => { return result + (activity.badge).number; }, 0); - const descriptorFn = (): string => { - return numberActivities.reduce((result, activity, index) => { - result = result + (activity.badge).getDescription(); - if (index < numberActivities.length - 1) { - result = `${result}\n`; - } + private fillContextMenuActions(actions: IAction[], e?: MouseEvent | GestureEvent) { + // Menu + const menuBarVisibility = getMenuBarVisibility(this.configurationService); + if (menuBarVisibility === 'compact' || menuBarVisibility === 'hidden' || menuBarVisibility === 'toggle') { + actions.unshift(...[toAction({ id: 'toggleMenuVisibility', label: localize('menu', "Menu"), checked: menuBarVisibility === 'compact', run: () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact') }), new Separator()]); + } - return result; - }, ''); - }; + if (menuBarVisibility === 'compact' && this.menuBarContainer && e?.target) { + if (isAncestor(e.target as Node, this.menuBarContainer)) { + actions.unshift(...[toAction({ id: 'hideCompactMenu', label: localize('hideMenu', "Hide Menu"), run: () => this.configurationService.updateValue('window.menuBarVisibility', 'toggle') }), new Separator()]); + } + } - return new NumberBadge(number, descriptorFn); + // Global Composite Bar + if (this.globalCompositeBar) { + actions.push(new Separator()); + actions.push(...this.globalCompositeBar.getContextMenuActions()); + } + actions.push(new Separator()); + actions.push(...this.getActivityBarContextMenuActions()); } private uninstallMenubar() { @@ -427,7 +265,6 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart if (this.menuBarContainer) { this.menuBarContainer.remove(); this.menuBarContainer = undefined; - this.registerKeyboardNavigationListeners(); } } @@ -439,64 +276,31 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart this.menuBarContainer = document.createElement('div'); this.menuBarContainer.classList.add('menubar'); - const content = assertIsDefined(this.content); - // below codes are changed by github1s - if (this.homeBarContainer) { - content.insertBefore(this.menuBarContainer, this.homeBarContainer.nextSibling); + const content = assertIsDefined(this.element); + /* below codes are changed by github1s */ + const homeBarContainer = this.element?.querySelector('.home-bar'); + if (homeBarContainer) { + content.insertBefore(this.menuBarContainer, homeBarContainer.nextSibling); } else { content.prepend(this.menuBarContainer); } - // above codes are changed by github1s + /* above codes are changed by github1s */ // Menubar: install a custom menu bar depending on configuration this.menuBar = this._register(this.instantiationService.createInstance(CustomMenubarControl)); this.menuBar.create(this.menuBarContainer); - this.registerKeyboardNavigationListeners(); - } - - protected override createContentArea(parent: HTMLElement): HTMLElement { - this.element = parent; - - this.content = document.createElement('div'); - this.content.classList.add('content'); - parent.appendChild(this.content); - - // below codes are changed by github1s - if (window?.vscodeWeb?.logo) { - this.createHomeBar(); - } - // above codes are changed by github1s - - // Install menubar if compact - if (getMenuBarVisibility(this.configurationService) === 'compact') { - this.installMenubar(); - } - - // View Containers action bar - this.compositeBarContainer = this.compositeBar.create(this.content); - - // Global action bar - this.globalActivitiesContainer = document.createElement('div'); - this.content.appendChild(this.globalActivitiesContainer); - - this.createGlobalActivityActionBar(this.globalActivitiesContainer); - - // Keyboard Navigation - this.registerKeyboardNavigationListeners(); - - return this.content; } private registerKeyboardNavigationListeners(): void { this.keyboardNavigationDisposables.clear(); - // Up/Down arrow on compact menu + // Up/Down or Left/Right arrow on compact menu if (this.menuBarContainer) { this.keyboardNavigationDisposables.add(addDisposableListener(this.menuBarContainer, EventType.KEY_DOWN, e => { const kbEvent = new StandardKeyboardEvent(e); if (kbEvent.equals(KeyCode.DownArrow) || kbEvent.equals(KeyCode.RightArrow)) { - this.compositeBar?.focus(); + this.focus(); } })); } @@ -506,7 +310,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart this.keyboardNavigationDisposables.add(addDisposableListener(this.compositeBarContainer, EventType.KEY_DOWN, e => { const kbEvent = new StandardKeyboardEvent(e); if (kbEvent.equals(KeyCode.DownArrow) || kbEvent.equals(KeyCode.RightArrow)) { - this.globalActivityActionBar?.focus(true); + this.globalCompositeBar?.focus(); } else if (kbEvent.equals(KeyCode.UpArrow) || kbEvent.equals(KeyCode.LeftArrow)) { this.menuBar?.toggleFocus(); } @@ -514,550 +318,350 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart } // Up arrow on global icons - if (this.globalActivitiesContainer) { - this.keyboardNavigationDisposables.add(addDisposableListener(this.globalActivitiesContainer, EventType.KEY_DOWN, e => { + if (this.globalCompositeBar) { + this.keyboardNavigationDisposables.add(addDisposableListener(this.globalCompositeBar.element, EventType.KEY_DOWN, e => { const kbEvent = new StandardKeyboardEvent(e); if (kbEvent.equals(KeyCode.UpArrow) || kbEvent.equals(KeyCode.LeftArrow)) { - this.compositeBar?.focus(this.getVisiblePaneCompositeIds().length - 1); + this.focus(this.getVisiblePaneCompositeIds().length - 1); } })); } } - // below codes are changed by github1s - private createHomeBar(): void { - const logo = window?.vscodeWeb?.logo as { icon?: string; title?: string; onClick?: () => void } | undefined; - - this.homeBarContainer = document.createElement('div'); - this.homeBarContainer.setAttribute('aria-label', logo?.title || 'Home'); - this.homeBarContainer.setAttribute('role', 'toolbar'); - this.homeBarContainer.classList.add('home-bar'); + override create(parent: HTMLElement): HTMLElement { + this.element = parent; + /* below codes are changed by github1s */ + const logo = window?.vscodeWeb?.logo as { icon?: string; title?: string; onClick?: () => void } | undefined; + const homeBarContainer = document.createElement('div'); + homeBarContainer.className = 'home-bar'; + if (logo?.icon) { + const logoImage = `url(${window.encodeURI(logo?.icon)})` + homeBarContainer.style.maskImage = logoImage; + homeBarContainer.style.webkitMaskImage = logoImage; + } if (logo?.onClick) { - this.homeBarContainer.classList.add('home-bar-clickable'); + homeBarContainer.onclick = logo.onClick; + homeBarContainer.classList.add('home-bar-clickable'); } + this.element.prepend(homeBarContainer); + /* above codes are changed by github1s */ - const homeBar = this._register(new ActionBar(this.homeBarContainer, { - actionViewItemProvider: action => this.instantiationService.createInstance(HomeActivityActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme), this.getActivityHoverOptions()), - orientation: ActionsOrientation.VERTICAL, - ariaLabel: logo?.title || 'Home', - animated: false, - preventLoopNavigation: true, - })); - - homeBar.push(this._register(new ActivityAction({ - id: 'workbench.actions.home', - name: logo?.title || 'Home', - classNames: [logo?.icon ? 'home-bar-custom-icon' : ''], - }))); - - const content = assertIsDefined(this.content); - content.appendChild(this.homeBarContainer); - // set custom logo - if (logo?.icon) { - const iconElement = this.homeBarContainer.querySelector('.home-bar-custom-icon') as HTMLElement; - if (iconElement?.style) { - const logoImage = `url(${window.encodeURI(logo?.icon)})` - iconElement.style.maskImage = logoImage; - iconElement.style.webkitMaskImage = logoImage; - } + // Install menubar if compact + if (getMenuBarVisibility(this.configurationService) === 'compact') { + this.installMenubar(); } - } - // above codes are changed by github1s - - private createGlobalActivityActionBar(container: HTMLElement): void { - this.globalActivityActionBar = this._register(new ActionBar(container, { - actionViewItemProvider: action => { - if (action.id === 'workbench.actions.manage') { - return this.instantiationService.createInstance(GlobalActivityActionViewItem, action as ActivityAction, () => this.compositeBar.getContextMenuActions(), (theme: IColorTheme) => this.getActivitybarItemColors(theme), this.getActivityHoverOptions()); - } - - if (action.id === 'workbench.actions.accounts') { - return this.instantiationService.createInstance(AccountsActivityActionViewItem, action as ActivityAction, () => this.compositeBar.getContextMenuActions(), (theme: IColorTheme) => this.getActivitybarItemColors(theme), this.getActivityHoverOptions()); - } - - throw new Error(`No view item for action '${action.id}'`); - }, - orientation: ActionsOrientation.VERTICAL, - ariaLabel: localize('manage', "Manage"), - animated: false, - preventLoopNavigation: true - })); - - this.globalActivityAction = this._register(new ActivityAction(this.createGlobalActivity())); - this._register(this.userDataProfileService.onDidChangeCurrentProfile(e => { - if (this.globalActivityAction) { - this.globalActivityAction.activity = this.createGlobalActivity(); - } - })); - if (this.accountsVisibilityPreference) { - this.accountsActivityAction = this._register(new ActivityAction({ - id: 'workbench.actions.accounts', - name: localize('accounts', "Accounts"), - classNames: ThemeIcon.asClassNameArray(ActivitybarPart.ACCOUNTS_ICON) - })); + // View Containers action bar + this.compositeBarContainer = super.create(this.element); - this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX }); + // Global action bar + if (this.globalCompositeBar) { + this.globalCompositeBar.create(this.element); } - this.globalActivityActionBar.push(this.globalActivityAction); - } + // Keyboard Navigation + this.registerKeyboardNavigationListeners(); - private createGlobalActivity(): IActivity { - return { - id: 'workbench.actions.manage', - name: localize('manage', "Manage"), - classNames: ThemeIcon.asClassNameArray(this.userDataProfileService.currentProfile.icon ? ThemeIcon.fromId(this.userDataProfileService.currentProfile.icon) : DEFAULT_ICON), - }; + return this.compositeBarContainer; } - private toggleAccountsActivity() { - if (!!this.accountsActivityAction === this.accountsVisibilityPreference) { - return; - } - if (this.globalActivityActionBar) { - if (this.accountsActivityAction) { - this.globalActivityActionBar.pull(ActivitybarPart.ACCOUNTS_ACTION_INDEX); - this.accountsActivityAction = undefined; + override layout(width: number, height: number): void { + if (this.menuBarContainer) { + if (this.options.orientation === ActionsOrientation.VERTICAL) { + height -= this.menuBarContainer.clientHeight; } else { - this.accountsActivityAction = this._register(new ActivityAction({ - id: 'workbench.actions.accounts', - name: localize('accounts', "Accounts"), - classNames: ThemeIcon.asClassNameArray(Codicon.account) - })); - this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX }); + width -= this.menuBarContainer.clientWidth; } } - - this.updateGlobalActivity(ACCOUNTS_ACTIVITY_ID); - } - - private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction; badgeAction: ToggleCompositeBadgeAction } { - let compositeActions = this.compositeActions.get(compositeId); - if (!compositeActions) { - const viewContainer = this.getViewContainer(compositeId); - if (viewContainer) { - const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); - compositeActions = { - activityAction: this.instantiationService.createInstance(ViewContainerActivityAction, this.toActivity(viewContainerModel), this.paneCompositePart), - pinnedAction: new ToggleCompositePinnedAction(this.toActivity(viewContainerModel), this.compositeBar), - badgeAction: new ToggleCompositeBadgeAction(this.toActivity(viewContainerModel), this.compositeBar) - }; + if (this.globalCompositeBar) { + if (this.options.orientation === ActionsOrientation.VERTICAL) { + height -= (this.globalCompositeBar.size() * ActivitybarPart.ACTION_HEIGHT); } else { - const cachedComposite = this.cachedViewContainers.filter(c => c.id === compositeId)[0]; - compositeActions = { - activityAction: this.instantiationService.createInstance(PlaceHolderViewContainerActivityAction, ActivitybarPart.toActivity(compositeId, compositeId, cachedComposite?.icon, undefined), this.paneCompositePart), - pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar), - badgeAction: new PlaceHolderToggleCompositeBadgeAction(compositeId, this.compositeBar) - }; + width -= this.globalCompositeBar.element.clientWidth; } - - this.compositeActions.set(compositeId, compositeActions); } - - return compositeActions; + super.layout(width, height); } - private onDidRegisterViewContainers(viewContainers: readonly ViewContainer[]): void { - for (const viewContainer of viewContainers) { - this.addComposite(viewContainer); - - // Pin it by default if it is new - const cachedViewContainer = this.cachedViewContainers.filter(({ id }) => id === viewContainer.id)[0]; - if (!cachedViewContainer) { - this.compositeBar.pin(viewContainer.id); - } - - // Active - const visibleViewContainer = this.paneCompositePart.getActivePaneComposite(); - if (visibleViewContainer?.getId() === viewContainer.id) { - this.compositeBar.activateComposite(viewContainer.id); - } - - const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); - this.updateActivity(viewContainer, viewContainerModel); - this.showOrHideViewContainer(viewContainer); - - const disposables = new DisposableStore(); - disposables.add(viewContainerModel.onDidChangeContainerInfo(() => this.updateActivity(viewContainer, viewContainerModel))); - disposables.add(viewContainerModel.onDidChangeActiveViewDescriptors(() => this.showOrHideViewContainer(viewContainer))); - - this.viewContainerDisposables.set(viewContainer.id, disposables); - } + getActivityBarContextMenuActions(): IAction[] { + const activityBarPositionMenu = this.menuService.createMenu(MenuId.ActivityBarPositionMenu, this.contextKeyService); + const positionActions: IAction[] = []; + createAndFillInContextMenuActions(activityBarPositionMenu, { shouldForwardArgs: true, renderShortTitle: true }, { primary: [], secondary: positionActions }); + activityBarPositionMenu.dispose(); + return [ + 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)) }) + ]; } - private onDidDeregisterViewContainer(viewContainer: ViewContainer): void { - const disposable = this.viewContainerDisposables.get(viewContainer.id); - disposable?.dispose(); - - this.viewContainerDisposables.delete(viewContainer.id); - this.removeComposite(viewContainer.id); - } - - private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void { - const activity: IActivity = this.toActivity(viewContainerModel); - const { activityAction, pinnedAction } = this.getCompositeActions(viewContainer.id); - activityAction.updateActivity(activity); - - if (pinnedAction instanceof PlaceHolderToggleCompositePinnedAction) { - pinnedAction.setActivity(activity); - } +} - this.saveCachedViewContainers(); - } +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.activityBarLocation.side', + title: { + value: localize('positionActivityBarSide', 'Move Activity Bar to Side'), + original: 'Move Activity Bar to Side', + mnemonicTitle: localize({ key: 'miSideActivityBar', comment: ['&& denotes a mnemonic'] }, "&&Side"), + }, + shortTitle: localize('side', "Side"), + category: Categories.View, + toggled: ContextKeyExpr.or(ContextKeyExpr.equals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.SIDE), ContextKeyExpr.and(ContextKeyExpr.equals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), TitleBarStyleContext.isEqualTo('native'))), + menu: [{ + id: MenuId.ActivityBarPositionMenu, + order: 1 + }, { + id: MenuId.CommandPalette, + when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.SIDE), + }] + }); + } + run(accessor: ServicesAccessor): void { + const configurationService = accessor.get(IConfigurationService); + configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_LOCATION, ActivityBarPosition.SIDE); + } +}); + +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.activityBarLocation.top', + title: { + value: localize('positionActivityBarTop', 'Move Activity Bar to Top'), + original: 'Move Activity Bar to Top', + mnemonicTitle: localize({ key: 'miTopActivityBar', comment: ['&& denotes a mnemonic'] }, "&&Top"), + }, + shortTitle: localize('top', "Top"), + category: Categories.View, + toggled: ContextKeyExpr.equals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), + menu: [{ + id: MenuId.ActivityBarPositionMenu, + when: TitleBarStyleContext.notEqualsTo('native'), + order: 2 + }, { + id: MenuId.CommandPalette, + when: ContextKeyExpr.and(ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.TOP), TitleBarStyleContext.notEqualsTo('native')), + }] + }); + } + run(accessor: ServicesAccessor): void { + const configurationService = accessor.get(IConfigurationService); + configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_LOCATION, ActivityBarPosition.TOP); + } +}); + +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'workbench.action.activityBarLocation.hide', + title: { + value: localize('hideActivityBar', 'Hide Activity Bar'), + original: 'Hide Activity Bar', + mnemonicTitle: localize({ key: 'miHideActivityBar', comment: ['&& denotes a mnemonic'] }, "&&Hidden"), + }, + shortTitle: localize('hide', "Hidden"), + category: Categories.View, + toggled: ContextKeyExpr.equals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.HIDDEN), + menu: [{ + id: MenuId.ActivityBarPositionMenu, + order: 3 + }, { + id: MenuId.CommandPalette, + when: ContextKeyExpr.notEquals(`config.${LayoutSettings.ACTIVITY_BAR_LOCATION}`, ActivityBarPosition.HIDDEN), + }] + }); + } + run(accessor: ServicesAccessor): void { + const configurationService = accessor.get(IConfigurationService); + configurationService.updateValue(LayoutSettings.ACTIVITY_BAR_LOCATION, ActivityBarPosition.HIDDEN); + } +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { + submenu: MenuId.ActivityBarPositionMenu, + title: localize('positionActivituBar', "Activity Bar Position"), + group: '3_workbench_layout_move', + order: 1 +}); + +MenuRegistry.appendMenuItem(MenuId.ViewContainerTitleContext, { + submenu: MenuId.ActivityBarPositionMenu, + title: localize('positionActivituBar', "Activity Bar Position"), + when: ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar)), + group: '3_workbench_layout_move', + order: 1 +}); + +MenuRegistry.appendMenuItem(MenuId.ViewTitleContext, { + submenu: MenuId.ActivityBarPositionMenu, + title: localize('positionActivituBar', "Activity Bar Position"), + when: ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar)), + group: '3_workbench_layout_move', + order: 1 +}); + +class SwitchSideBarViewAction extends Action2 { - private toActivity(viewContainerModel: IViewContainerModel): IActivity { - return ActivitybarPart.toActivity(viewContainerModel.viewContainer.id, viewContainerModel.title, viewContainerModel.icon, viewContainerModel.keybindingId); + constructor( + desc: Readonly, + private readonly offset: number + ) { + super(desc); } - private static toActivity(id: string, name: string, icon: URI | ThemeIcon | undefined, keybindingId: string | undefined): IActivity { - let classNames: string[] | undefined = undefined; - let iconUrl: URI | undefined = undefined; - if (URI.isUri(icon)) { - iconUrl = icon; - const cssUrl = asCSSUrl(icon); - const hash = new StringSHA1(); - hash.update(cssUrl); - const iconId = `activity-${id.replace(/\./g, '-')}-${hash.digest()}`; - const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${iconId}`; - classNames = [iconId, 'uri-icon']; - createCSSRule(iconClass, ` - mask: ${cssUrl} no-repeat 50% 50%; - mask-size: 24px; - -webkit-mask: ${cssUrl} no-repeat 50% 50%; - -webkit-mask-size: 24px; - `); - } else if (ThemeIcon.isThemeIcon(icon)) { - classNames = ThemeIcon.asClassNameArray(icon); - } + async run(accessor: ServicesAccessor): Promise { + const paneCompositeService = accessor.get(IPaneCompositePartService); - return { id, name, classNames, iconUrl, keybindingId }; - } + const visibleViewletIds = paneCompositeService.getVisiblePaneCompositeIds(ViewContainerLocation.Sidebar); - private showOrHideViewContainer(viewContainer: ViewContainer): void { - let contextKey = this.enabledViewContainersContextKeys.get(viewContainer.id); - if (!contextKey) { - contextKey = this.contextKeyService.createKey(getEnabledViewContainerContextKey(viewContainer.id), false); - this.enabledViewContainersContextKeys.set(viewContainer.id, contextKey); - } - if (this.shouldBeHidden(viewContainer)) { - contextKey.set(false); - this.hideComposite(viewContainer.id); - } else { - contextKey.set(true); - this.addComposite(viewContainer); - } - } - - private shouldBeHidden(viewContainerOrId: string | ViewContainer, cachedViewContainer?: ICachedViewContainer): boolean { - const viewContainer = isString(viewContainerOrId) ? this.getViewContainer(viewContainerOrId) : viewContainerOrId; - const viewContainerId = isString(viewContainerOrId) ? viewContainerOrId : viewContainerOrId.id; - - if (viewContainer) { - if (viewContainer.hideIfEmpty) { - if (this.viewDescriptorService.getViewContainerModel(viewContainer).activeViewDescriptors.length > 0) { - return false; - } - } else { - return false; - } + const activeViewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); + if (!activeViewlet) { + return; } - - // Check cache only if extensions are not yet registered and current window is not native (desktop) remote connection window - if (!this.hasExtensionsRegistered && !(this.environmentService.remoteAuthority && isNative)) { - cachedViewContainer = cachedViewContainer || this.cachedViewContainers.find(({ id }) => id === viewContainerId); - - // Show builtin ViewContainer if not registered yet - if (!viewContainer && cachedViewContainer?.isBuiltin && cachedViewContainer?.visible) { - return false; - } - - if (cachedViewContainer?.views?.length) { - return cachedViewContainer.views.every(({ when }) => !!when && !this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(when))); + let targetViewletId: string | undefined; + for (let i = 0; i < visibleViewletIds.length; i++) { + if (visibleViewletIds[i] === activeViewlet.getId()) { + targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + this.offset) % visibleViewletIds.length]; + break; } } - return true; - } - - private addComposite(viewContainer: ViewContainer): void { - this.compositeBar.addComposite({ id: viewContainer.id, name: typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.value, order: viewContainer.order, requestedIndex: viewContainer.requestedIndex }); + await paneCompositeService.openPaneComposite(targetViewletId, ViewContainerLocation.Sidebar, true); } +} - private hideComposite(compositeId: string): void { - this.compositeBar.hideComposite(compositeId); - - const compositeActions = this.compositeActions.get(compositeId); - if (compositeActions) { - compositeActions.activityAction.dispose(); - compositeActions.pinnedAction.dispose(); - this.compositeActions.delete(compositeId); +registerAction2( + class PreviousSideBarViewAction extends SwitchSideBarViewAction { + constructor() { + super({ + id: 'workbench.action.previousSideBarView', + title: { value: localize('previousSideBarView', "Previous Primary Side Bar View"), original: 'Previous Primary Side Bar View' }, + category: Categories.View, + f1: true + }, -1); } } +); - private removeComposite(compositeId: string): void { - this.compositeBar.removeComposite(compositeId); - - const compositeActions = this.compositeActions.get(compositeId); - if (compositeActions) { - compositeActions.activityAction.dispose(); - compositeActions.pinnedAction.dispose(); - this.compositeActions.delete(compositeId); +registerAction2( + class NextSideBarViewAction extends SwitchSideBarViewAction { + constructor() { + super({ + id: 'workbench.action.nextSideBarView', + title: { value: localize('nextSideBarView', "Next Primary Side Bar View"), original: 'Next Primary Side Bar View' }, + category: Categories.View, + f1: true + }, 1); } } +); - getPinnedPaneCompositeIds(): string[] { - const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id); - return this.getViewContainers() - .filter(v => this.compositeBar.isPinned(v.id)) - .sort((v1, v2) => pinnedCompositeIds.indexOf(v1.id) - pinnedCompositeIds.indexOf(v2.id)) - .map(v => v.id); - } - - getVisiblePaneCompositeIds(): string[] { - return this.compositeBar.getVisibleComposites() - .filter(v => this.paneCompositePart.getActivePaneComposite()?.getId() === v.id || this.compositeBar.isPinned(v.id)) - .map(v => v.id); - } - - focus(): void { - this.compositeBar.focus(); - } - - override updateStyles(): void { - super.updateStyles(); - - const container = assertIsDefined(this.getContainer()); - const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || ''; - container.style.backgroundColor = background; - - const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || ''; - container.classList.toggle('bordered', !!borderColor); - container.style.borderColor = borderColor ? borderColor : ''; - } - - private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors { - return { - activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND), - inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND), - activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER), - activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND), - badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), - badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), - dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER), - activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined, - }; - } - - override layout(width: number, height: number): void { - if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) { - return; +registerAction2( + class FocusActivityBarAction extends Action2 { + constructor() { + super({ + id: 'workbench.action.focusActivityBar', + title: { value: localize('focusActivityBar', "Focus Activity Bar"), original: 'Focus Activity Bar' }, + category: Categories.View, + f1: true + }); } - // Layout contents - const contentAreaSize = super.layoutContents(width, height).contentSize; - - // Layout composite bar - let availableHeight = contentAreaSize.height; - if (this.menuBarContainer) { - availableHeight -= this.menuBarContainer.clientHeight; + async run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + layoutService.focusPart(Parts.ACTIVITYBAR_PART); } - if (this.globalActivityActionBar) { - availableHeight -= (this.globalActivityActionBar.viewItems.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing - } - this.compositeBar.layout(new Dimension(width, availableHeight)); - } + }); - private getViewContainer(id: string): ViewContainer | undefined { - const viewContainer = this.viewDescriptorService.getViewContainerById(id); - return viewContainer && this.viewDescriptorService.getViewContainerLocation(viewContainer) === this.location ? viewContainer : undefined; - } +registerThemingParticipant((theme, collector) => { - private getViewContainers(): readonly ViewContainer[] { - return this.viewDescriptorService.getViewContainersByLocation(this.location); + const activityBarActiveBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER); + if (activityBarActiveBorderColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { + border-left-color: ${activityBarActiveBorderColor}; + } + `); } - private onDidPinnedViewContainersStorageValueChange(e: IProfileStorageValueChangeEvent): void { - if (this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) { - this._pinnedViewContainersValue = undefined; - this._cachedViewContainers = undefined; - - const newCompositeItems: ICompositeBarItem[] = []; - const compositeItems = this.compositeBar.getCompositeBarItems(); - - for (const cachedViewContainer of this.cachedViewContainers) { - newCompositeItems.push({ - id: cachedViewContainer.id, - name: cachedViewContainer.name, - order: cachedViewContainer.order, - pinned: cachedViewContainer.pinned, - visible: !!compositeItems.find(({ id }) => id === cachedViewContainer.id) - }); + const activityBarActiveFocusBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_FOCUS_BORDER); + if (activityBarActiveFocusBorderColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus::before { + visibility: hidden; } - for (let index = 0; index < compositeItems.length; index++) { - // Add items currently exists but does not exist in new. - if (!newCompositeItems.some(({ id }) => id === compositeItems[index].id)) { - const viewContainer = this.viewDescriptorService.getViewContainerById(compositeItems[index].id); - newCompositeItems.splice(index, 0, { - ...compositeItems[index], - pinned: true, - visible: true, - order: viewContainer?.order, - }); - } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { + visibility: visible; + border-left-color: ${activityBarActiveFocusBorderColor}; } - - this.compositeBar.setCompositeBarItems(newCompositeItems); - } + `); } - private saveCachedViewContainers(): void { - const state: ICachedViewContainer[] = []; - - const compositeItems = this.compositeBar.getCompositeBarItems(); - for (const compositeItem of compositeItems) { - const viewContainer = this.getViewContainer(compositeItem.id); - if (viewContainer) { - const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); - const views: { when: string | undefined }[] = []; - for (const { when } of viewContainerModel.allViewDescriptors) { - views.push({ when: when ? when.serialize() : undefined }); - } - state.push({ - id: compositeItem.id, - name: viewContainerModel.title, - icon: URI.isUri(viewContainerModel.icon) && this.environmentService.remoteAuthority ? undefined : viewContainerModel.icon, // Do not cache uri icons with remote connection - views, - pinned: compositeItem.pinned, - order: compositeItem.order, - visible: compositeItem.visible, - isBuiltin: !viewContainer.extensionId - }); - } else { - state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: false, isBuiltin: false }); + const activityBarActiveBackgroundColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND); + if (activityBarActiveBackgroundColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator { + z-index: 0; + background-color: ${activityBarActiveBackgroundColor}; } - } - - this.storeCachedViewContainersState(state); - } - - private _cachedViewContainers: ICachedViewContainer[] | undefined = undefined; - private get cachedViewContainers(): ICachedViewContainer[] { - if (this._cachedViewContainers === undefined) { - this._cachedViewContainers = this.getPinnedViewContainers(); - for (const placeholderViewContainer of this.getPlaceholderViewContainers()) { - const cachedViewContainer = this._cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0]; - if (cachedViewContainer) { - cachedViewContainer.name = placeholderViewContainer.name; - cachedViewContainer.icon = placeholderViewContainer.themeIcon ? placeholderViewContainer.themeIcon : - placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined; - if (URI.isUri(cachedViewContainer.icon) && this.environmentService.remoteAuthority) { - cachedViewContainer.icon = undefined; // Do not cache uri icons with remote connection - } - cachedViewContainer.views = placeholderViewContainer.views; - cachedViewContainer.isBuiltin = placeholderViewContainer.isBuiltin; - } + `); + } + + // Styling with Outline color (e.g. high contrast theme) + const outline = theme.getColor(activeContrastBorder); + if (outline) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:before { + content: ""; + position: absolute; + top: 8px; + left: 8px; + height: 32px; + width: 32px; + z-index: 1; } - } - - return this._cachedViewContainers; - } - - private storeCachedViewContainersState(cachedViewContainers: ICachedViewContainer[]): void { - this.setPinnedViewContainers(cachedViewContainers.map(({ id, pinned, visible, order }) => ({ - id, - pinned, - visible, - order - }))); - - this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views, isBuiltin }) => ({ - id, - iconUrl: URI.isUri(icon) ? icon : undefined, - themeIcon: ThemeIcon.isThemeIcon(icon) ? icon : undefined, - name, - isBuiltin, - views - }))); - } - - private getPinnedViewContainers(): IPinnedViewContainer[] { - return JSON.parse(this.pinnedViewContainersValue); - } - - private setPinnedViewContainers(pinnedViewContainers: IPinnedViewContainer[]): void { - this.pinnedViewContainersValue = JSON.stringify(pinnedViewContainers); - } - - private _pinnedViewContainersValue: string | undefined; - private get pinnedViewContainersValue(): string { - if (!this._pinnedViewContainersValue) { - this._pinnedViewContainersValue = this.getStoredPinnedViewContainersValue(); - } - return this._pinnedViewContainersValue; - } - - private set pinnedViewContainersValue(pinnedViewContainersValue: string) { - if (this.pinnedViewContainersValue !== pinnedViewContainersValue) { - this._pinnedViewContainersValue = pinnedViewContainersValue; - this.setStoredPinnedViewContainersValue(pinnedViewContainersValue); - } - } - - private getStoredPinnedViewContainersValue(): string { - return this.storageService.get(ActivitybarPart.PINNED_VIEW_CONTAINERS, StorageScope.PROFILE, '[]'); - } - - private setStoredPinnedViewContainersValue(value: string): void { - this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.PROFILE, StorageTarget.USER); - } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.profile-activity-item:before { + top: -6px; + } - private getPlaceholderViewContainers(): IPlaceholderViewContainer[] { - return JSON.parse(this.placeholderViewContainersValue); - } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before { + outline: 1px solid; + } - private setPlaceholderViewContainers(placeholderViewContainers: IPlaceholderViewContainer[]): void { - this.placeholderViewContainersValue = JSON.stringify(placeholderViewContainers); - } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { + outline: 1px dashed; + } - private _placeholderViewContainersValue: string | undefined; - private get placeholderViewContainersValue(): string { - if (!this._placeholderViewContainersValue) { - this._placeholderViewContainersValue = this.getStoredPlaceholderViewContainersValue(); - } + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before { + border-left-color: ${outline}; + } - return this._placeholderViewContainersValue; + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before, + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { + outline-color: ${outline}; + } + `); } - private set placeholderViewContainersValue(placeholderViewContainesValue: string) { - if (this.placeholderViewContainersValue !== placeholderViewContainesValue) { - this._placeholderViewContainersValue = placeholderViewContainesValue; - this.setStoredPlaceholderViewContainersValue(placeholderViewContainesValue); + // Styling without outline color + else { + const focusBorderColor = theme.getColor(focusBorder); + if (focusBorderColor) { + collector.addRule(` + .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before { + border-left-color: ${focusBorderColor}; + } + `); } } - - private getStoredPlaceholderViewContainersValue(): string { - return this.storageService.get(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, StorageScope.PROFILE, '[]'); - } - - private setStoredPlaceholderViewContainersValue(value: string): void { - this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.PROFILE, StorageTarget.MACHINE); - } - - private get accountsVisibilityPreference(): boolean { - return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, true); - } - - private set accountsVisibilityPreference(value: boolean) { - this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.PROFILE, StorageTarget.USER); - } - - toJSON(): object { - return { - type: Parts.ACTIVITYBAR_PART - }; - } -} +}); diff --git a/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/vscode-web/src/vs/workbench/browser/parts/globalCompositeBar.ts similarity index 52% rename from vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts rename to vscode-web/src/vs/workbench/browser/parts/globalCompositeBar.ts index 6908c7d13..0a3a8b793 100644 --- a/vscode-web/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/vscode-web/src/vs/workbench/browser/parts/globalCompositeBar.ts @@ -3,135 +3,212 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/activityaction'; import { localize } from 'vs/nls'; -import { EventType, addDisposableListener, EventHelper, append, $, clearNode, hide, show } from 'vs/base/browser/dom'; +import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ACCOUNTS_ACTIVITY_ID, GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; +import { IActivity, IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { CompoisteBarActionViewItem, CompositeBarAction, IActivityHoverOptions, ICompositeBarActionViewItemOptions, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions'; +import { Codicon } from 'vs/base/common/codicons'; +import { ThemeIcon } from 'vs/base/common/themables'; +import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { Action, IAction, Separator, SubmenuAction, toAction } from 'vs/base/common/actions'; +import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { addDisposableListener, EventType, append, clearNode, hide, show, EventHelper, $ } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch'; -import { Action, IAction, Separator, SubmenuAction, toAction } from 'vs/base/common/actions'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IMenuService, MenuId, IMenu, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositeBadgeAction, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions'; -import { Categories } from 'vs/platform/action/common/actionCommonCategories'; -import { IActivity } from 'vs/workbench/common/activity'; -import { ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_ACTIVE_BORDER } from 'vs/workbench/common/theme'; -import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { runWhenIdle } from 'vs/base/common/async'; +import { Lazy } from 'vs/base/common/lazy'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { AuthenticationSessionInfo, getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; -import { AuthenticationSessionAccount, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; -import { ViewContainerLocation } from 'vs/workbench/common/views'; -import { IPaneCompositePart } from 'vs/workbench/browser/parts/paneCompositePart'; -import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { ILogService } from 'vs/platform/log/common/log'; +import { IProductService } from 'vs/platform/product/common/productService'; import { ISecretStorageService } from 'vs/platform/secrets/common/secrets'; +import { AuthenticationSessionInfo, getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; +import { AuthenticationSessionAccount, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { runWhenIdle } from 'vs/base/common/async'; -import { Lazy } from 'vs/base/common/lazy'; +import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { DEFAULT_ICON } from 'vs/workbench/services/userDataProfile/common/userDataProfileIcons'; +import { isString } from 'vs/base/common/types'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND } from 'vs/workbench/common/theme'; -export class ViewContainerActivityAction extends ActivityAction { +export class GlobalCompositeBar extends Disposable { - private static readonly preventDoubleClickDelay = 300; + private static readonly ACCOUNTS_ACTION_INDEX = 0; + static readonly ACCOUNTS_ICON = registerIcon('accounts-view-bar-icon', Codicon.account, localize('accountsViewBarIcon', "Accounts icon in the view bar.")); - private lastRun = 0; + readonly element: HTMLElement; + + private readonly globalActivityAction = this._register(new Action(GLOBAL_ACTIVITY_ID)); + private readonly accountAction = this._register(new Action(ACCOUNTS_ACTIVITY_ID)); + private readonly globalActivityActionBar: ActionBar; constructor( - activity: IActivity, - private readonly paneCompositePart: IPaneCompositePart, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @IConfigurationService private readonly configurationService: IConfigurationService + private readonly contextMenuActionsProvider: () => IAction[], + private readonly colors: (theme: IColorTheme) => ICompositeBarColors, + private readonly activityHoverOptions: IActivityHoverOptions, + @IConfigurationService configurationService: IConfigurationService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IStorageService private readonly storageService: IStorageService, + @IExtensionService private readonly extensionService: IExtensionService, ) { - super(activity); + super(); + + this.element = document.createElement('div'); + const anchorAlignment = configurationService.getValue('workbench.sideBar.location') === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT; + const anchorAxisAlignment = AnchorAxisAlignment.HORIZONTAL; + this.globalActivityActionBar = this._register(new ActionBar(this.element, { + actionViewItemProvider: action => { + if (action.id === GLOBAL_ACTIVITY_ID) { + return this.instantiationService.createInstance(GlobalActivityActionViewItem, this.contextMenuActionsProvider, { colors: this.colors, hoverOptions: this.activityHoverOptions }, anchorAlignment, anchorAxisAlignment); + } + + if (action.id === ACCOUNTS_ACTIVITY_ID) { + return this.instantiationService.createInstance(AccountsActivityActionViewItem, + this.contextMenuActionsProvider, + { + colors: this.colors, + hoverOptions: this.activityHoverOptions + }, + anchorAlignment, + anchorAxisAlignment, + (actions: IAction[]) => { + actions.unshift(...[ + toAction({ id: 'hideAccounts', label: localize('hideAccounts', "Hide Accounts"), run: () => this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.PROFILE, StorageTarget.USER) }), + new Separator() + ]); + }); + } + + throw new Error(`No view item for action '${action.id}'`); + }, + orientation: ActionsOrientation.VERTICAL, + ariaLabel: localize('manage', "Manage"), + animated: false, + preventLoopNavigation: true + })); + + if (this.accountsVisibilityPreference) { + this.globalActivityActionBar.push(this.accountAction, { index: GlobalCompositeBar.ACCOUNTS_ACTION_INDEX }); + } + + this.globalActivityActionBar.push(this.globalActivityAction); + + this.registerListeners(); } - updateActivity(activity: IActivity): void { - this.activity = activity; + private registerListeners(): void { + // Extension registration + const disposables = this._register(new DisposableStore()); + this._register(this.extensionService.onDidRegisterExtensions(() => { + this.storageService.onDidChangeValue(StorageScope.PROFILE, AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, disposables)(() => this.toggleAccountsActivity(), this, disposables); + })); } - override async run(event: { preserveFocus: boolean }): Promise { - if (event instanceof MouseEvent && event.button === 2) { - return; // do not run on right click - } + create(parent: HTMLElement): void { + parent.appendChild(this.element); + } - // prevent accident trigger on a doubleclick (to help nervous people) - const now = Date.now(); - if (now > this.lastRun /* https://github.com/microsoft/vscode/issues/25830 */ && now - this.lastRun < ViewContainerActivityAction.preventDoubleClickDelay) { - return; - } - this.lastRun = now; - - const sideBarVisible = this.layoutService.isVisible(Parts.SIDEBAR_PART); - const activeViewlet = this.paneCompositePart.getActivePaneComposite(); - const focusBehavior = this.configurationService.getValue('workbench.activityBar.iconClickBehavior'); - - const focus = (event && 'preserveFocus' in event) ? !event.preserveFocus : true; - if (sideBarVisible && activeViewlet?.getId() === this.activity.id) { - switch (focusBehavior) { - case 'focus': - this.logAction('refocus'); - this.paneCompositePart.openPaneComposite(this.activity.id, focus); - break; - case 'toggle': - default: - // Hide sidebar if selected viewlet already visible - this.logAction('hide'); - this.layoutService.setPartHidden(true, Parts.SIDEBAR_PART); - break; - } + focus(): void { + this.globalActivityActionBar.focus(true); + } + + size(): number { + return this.globalActivityActionBar.viewItems.length; + } + + getContextMenuActions(): IAction[] { + return [toAction({ id: 'toggleAccountsVisibility', label: localize('accounts', "Accounts"), checked: this.accountsVisibilityPreference, run: () => this.accountsVisibilityPreference = !this.accountsVisibilityPreference })]; + } + private toggleAccountsActivity() { + if (this.globalActivityActionBar.length() === 2 && this.accountsVisibilityPreference) { return; } + if (this.globalActivityActionBar.length() === 2) { + this.globalActivityActionBar.pull(GlobalCompositeBar.ACCOUNTS_ACTION_INDEX); + } else { + this.globalActivityActionBar.push(this.accountAction, { index: GlobalCompositeBar.ACCOUNTS_ACTION_INDEX }); + } + } - this.logAction('show'); - await this.paneCompositePart.openPaneComposite(this.activity.id, focus); - - return this.activate(); + private get accountsVisibilityPreference(): boolean { + return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.PROFILE, true); } - private logAction(action: string) { - type ActivityBarActionClassification = { - owner: 'sbatten'; - comment: 'Event logged when an activity bar action is triggered.'; - viewletId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The view in the activity bar for which the action was performed.' }; - action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The action that was performed. e.g. "hide", "show", or "refocus"' }; - }; - this.telemetryService.publicLog2<{ viewletId: String; action: String }, ActivityBarActionClassification>('activityBarAction', { viewletId: this.activity.id, action }); + private set accountsVisibilityPreference(value: boolean) { + this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.PROFILE, StorageTarget.USER); } } -abstract class AbstractGlobalActivityActionViewItem extends ActivityActionViewItem { +abstract class AbstractGlobalActivityActionViewItem extends CompoisteBarActionViewItem { constructor( - action: ActivityAction, - private contextMenuActionsProvider: () => IAction[], - options: IActivityActionViewItemOptions, + private readonly menuId: MenuId, + action: CompositeBarAction, + options: ICompositeBarActionViewItemOptions, + private readonly contextMenuActionsProvider: () => IAction[], + private readonly anchorAlignment: AnchorAlignment | undefined, + private readonly anchorAxisAlignment: AnchorAxisAlignment | undefined, @IThemeService themeService: IThemeService, @IHoverService hoverService: IHoverService, - @IMenuService protected readonly menuService: IMenuService, - @IContextMenuService protected readonly contextMenuService: IContextMenuService, - @IContextKeyService protected readonly contextKeyService: IContextKeyService, + @IMenuService private readonly menuService: IMenuService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService, @IKeybindingService keybindingService: IKeybindingService, + @IActivityService private readonly activityService: IActivityService, ) { - super(action, options, () => true, themeService, hoverService, configurationService, keybindingService); + super(action, { draggable: false, icon: true, hasPopup: true, ...options }, () => true, themeService, hoverService, configurationService, keybindingService); + + this.updateItemActivity(); + this._register(this.activityService.onDidChangeActivity(viewContainerOrAction => { + if (isString(viewContainerOrAction) && viewContainerOrAction === this.compositeBarActionItem.id) { + this.updateItemActivity(); + } + })); + } + + private updateItemActivity(): void { + const activities = this.activityService.getActivity(this.compositeBarActionItem.id); + let activity = activities[0]; + if (activity) { + const { badge, priority } = activity; + if (badge instanceof NumberBadge && activities.length > 1) { + const cumulativeNumberBadge = this.getCumulativeNumberBadge(activities, priority ?? 0); + activity = { badge: cumulativeNumberBadge }; + } + } + (this.action as CompositeBarAction).activity = activity; + } + + private getCumulativeNumberBadge(activityCache: IActivity[], priority: number): NumberBadge { + const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && (activity.priority ?? 0) === priority); + const number = numberActivities.reduce((result, activity) => { return result + (activity.badge).number; }, 0); + const descriptorFn = (): string => { + return numberActivities.reduce((result, activity, index) => { + result = result + (activity.badge).getDescription(); + if (index < numberActivities.length - 1) { + result = `${result}\n`; + } + + return result; + }, ''); + }; + + return new NumberBadge(number, descriptorFn); } override render(container: HTMLElement): void { @@ -178,81 +255,15 @@ abstract class AbstractGlobalActivityActionViewItem extends ActivityActionViewIt return this.contextMenuActionsProvider(); } - protected abstract run(): Promise; -} - -// below codes are changed by github1s -// Add a button to the top of menubar which is used to jump back to GitHub -export class HomeActivityActionViewItem extends ActivityActionViewItem { - - static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator'; - - constructor( - action: ActivityAction, - colors: (theme: IColorTheme) => ICompositeBarColors, - hoverOptions: IActivityHoverOptions, - @IThemeService themeService: IThemeService, - @IHoverService hoverService: IHoverService, - @IConfigurationService configurationService: IConfigurationService, - @IKeybindingService keybindingService: IKeybindingService, - ) { - super(action, { draggable: false, colors, icon: true, hasPopup: true, hoverOptions }, () => true, themeService, hoverService, configurationService, keybindingService); - } - - override render(container: HTMLElement): void { - super.render(container); - - this._register(addDisposableListener(this.container, EventType.CLICK, (e: MouseEvent) => { - EventHelper.stop(e, true); - window?.vscodeWeb?.logo?.onClick?.(); - })); - - this._register(addDisposableListener(this.container, EventType.KEY_UP, (e: KeyboardEvent) => { - let event = new StandardKeyboardEvent(e); - if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { - EventHelper.stop(e, true); - window?.vscodeWeb?.logo?.onClick?.(); - } - })); - - this._register(addDisposableListener(this.container, TouchEventType.Tap, (e: GestureEvent) => { - EventHelper.stop(e, true); - window?.vscodeWeb?.logo?.onClick?.(); - })); - } -} -// above codes are changed by github1s - -class MenuActivityActionViewItem extends AbstractGlobalActivityActionViewItem { - - constructor( - private readonly menuId: MenuId, - action: ActivityAction, - contextMenuActionsProvider: () => IAction[], - icon: boolean, - colors: (theme: IColorTheme) => ICompositeBarColors, - hoverOptions: IActivityHoverOptions, - @IThemeService themeService: IThemeService, - @IHoverService hoverService: IHoverService, - @IMenuService menuService: IMenuService, - @IContextMenuService contextMenuService: IContextMenuService, - @IContextKeyService contextKeyService: IContextKeyService, - @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IKeybindingService keybindingService: IKeybindingService, - ) { - super(action, contextMenuActionsProvider, { draggable: false, colors, icon, hasPopup: true, hoverOptions }, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); - } - - protected async run(): Promise { + private async run(): Promise { const disposables = new DisposableStore(); const menu = disposables.add(this.menuService.createMenu(this.menuId, this.contextKeyService)); const actions = await this.resolveMainMenuActions(menu, disposables); this.contextMenuService.showContextMenu({ - getAnchor: () => this.container, - anchorAlignment: this.configurationService.getValue('workbench.sideBar.location') === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT, - anchorAxisAlignment: AnchorAxisAlignment.HORIZONTAL, + getAnchor: () => this.label, + anchorAlignment: this.anchorAlignment, + anchorAxisAlignment: this.anchorAxisAlignment, getActions: () => actions, onHide: () => disposables.dispose(), menuActionOptions: { renderShortTitle: true }, @@ -265,10 +276,9 @@ class MenuActivityActionViewItem extends AbstractGlobalActivityActionViewItem { createAndFillInActionBarActions(menu, { renderShortTitle: true }, { primary: [], secondary: actions }); return actions; } - } -export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { +export class AccountsActivityActionViewItem extends AbstractGlobalActivityActionViewItem { static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts'; @@ -279,10 +289,11 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { private sessionFromEmbedder = new Lazy>(() => getCurrentAuthenticationSessionInfo(this.secretStorageService, this.productService)); constructor( - action: ActivityAction, contextMenuActionsProvider: () => IAction[], - colors: (theme: IColorTheme) => ICompositeBarColors, - activityHoverOptions: IActivityHoverOptions, + options: ICompositeBarActionViewItemOptions, + anchorAlignment: AnchorAlignment | undefined, + anchorAxisAlignment: AnchorAxisAlignment | undefined, + private readonly fillContextMenuActions: (actions: IAction[]) => void, @IThemeService themeService: IThemeService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IHoverService hoverService: IHoverService, @@ -293,12 +304,19 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService private readonly productService: IProductService, @IConfigurationService configurationService: IConfigurationService, - @IStorageService private readonly storageService: IStorageService, @IKeybindingService keybindingService: IKeybindingService, @ISecretStorageService private readonly secretStorageService: ISecretStorageService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IActivityService activityService: IActivityService, + @IInstantiationService instantiationService: IInstantiationService, ) { - super(MenuId.AccountsContext, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); + const action = instantiationService.createInstance(CompositeBarAction, { + id: ACCOUNTS_ACTIVITY_ID, + name: localize('accounts', "Accounts"), + classNames: ThemeIcon.asClassNameArray(GlobalCompositeBar.ACCOUNTS_ICON) + }); + super(MenuId.AccountsContext, action, options, contextMenuActionsProvider, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); + this._register(action); this.registerListeners(); this.initialize(); } @@ -333,6 +351,9 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { // Resolving the menu doesn't need to happen immediately, so we can wait until after the workbench has been restored // and only run this when the system is idle. await this.lifecycleService.when(LifecyclePhase.Restored); + if (this._store.isDisposed) { + return; + } const disposable = this._register(runWhenIdle(async () => { await this.doInitialize(); disposable.dispose(); @@ -427,12 +448,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { protected override async resolveContextMenuActions(disposables: DisposableStore): Promise { const actions = await super.resolveContextMenuActions(disposables); - - actions.unshift(...[ - toAction({ id: 'hideAccounts', label: localize('hideAccounts', "Hide Accounts"), run: () => this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.PROFILE, StorageTarget.USER) }), - new Separator() - ]); - + this.fillContextMenuActions(actions); return actions; } @@ -511,20 +527,16 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem { //#endregion } -export interface IProfileActivity extends IActivity { - readonly icon: boolean; -} - -export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { +export class GlobalActivityActionViewItem extends AbstractGlobalActivityActionViewItem { private profileBadge: HTMLElement | undefined; private profileBadgeContent: HTMLElement | undefined; constructor( - action: ActivityAction, contextMenuActionsProvider: () => IAction[], - colors: (theme: IColorTheme) => ICompositeBarColors, - activityHoverOptions: IActivityHoverOptions, + options: ICompositeBarActionViewItemOptions, + anchorAlignment: AnchorAlignment | undefined, + anchorAxisAlignment: AnchorAxisAlignment | undefined, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, @IThemeService themeService: IThemeService, @IHoverService hoverService: IHoverService, @@ -534,8 +546,22 @@ export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IKeybindingService keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService, + @IActivityService activityService: IActivityService, ) { - super(MenuId.GlobalActivity, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); + const action = instantiationService.createInstance(CompositeBarAction, { + id: GLOBAL_ACTIVITY_ID, + name: localize('manage', "Manage"), + classNames: ThemeIcon.asClassNameArray(userDataProfileService.currentProfile.icon ? ThemeIcon.fromId(userDataProfileService.currentProfile.icon) : DEFAULT_ICON) + }); + super(MenuId.GlobalActivity, action, options, contextMenuActionsProvider, anchorAlignment, anchorAxisAlignment, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, keybindingService, activityService); + this._register(action); + this._register(this.userDataProfileService.onDidChangeCurrentProfile(e => { + action.compositeBarActionItem = { + ...action.compositeBarActionItem, + classNames: ThemeIcon.asClassNameArray(userDataProfileService.currentProfile.icon ? ThemeIcon.fromId(userDataProfileService.currentProfile.icon) : DEFAULT_ICON) + }; + })); } override render(container: HTMLElement): void { @@ -558,7 +584,7 @@ export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { return; } - if ((this.action as ActivityAction).getBadge()) { + if ((this.action as CompositeBarAction).activity) { return; } @@ -571,201 +597,70 @@ export class GlobalActivityActionViewItem extends MenuActivityActionViewItem { show(this.profileBadge); } - protected override updateBadge(): void { - super.updateBadge(); + protected override updateActivity(): void { + super.updateActivity(); this.updateProfileBadge(); } protected override computeTitle(): string { - return this.userDataProfileService.currentProfile.isDefault ? super.computeTitle() : localize('manage', "Manage {0} (Profile)", this.userDataProfileService.currentProfile.name); + return this.userDataProfileService.currentProfile.isDefault ? super.computeTitle() : localize('manage profile', "Manage {0} (Profile)", this.userDataProfileService.currentProfile.name); } } -export class PlaceHolderViewContainerActivityAction extends ViewContainerActivityAction { } +export class SimpleAccountActivityActionViewItem extends AccountsActivityActionViewItem { -export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinnedAction { - - constructor(id: string, compositeBar: ICompositeBar) { - super({ id, name: id, classNames: undefined }, compositeBar); - } - - setActivity(activity: IActivity): void { - this.label = activity.name; - } -} - -export class PlaceHolderToggleCompositeBadgeAction extends ToggleCompositeBadgeAction { - - constructor(id: string, compositeBar: ICompositeBar) { - super({ id, name: id, classNames: undefined }, compositeBar); - } - - setActivity(activity: IActivity): void { - this.label = activity.name; + constructor( + hoverOptions: IActivityHoverOptions, + @IThemeService themeService: IThemeService, + @ILifecycleService lifecycleService: ILifecycleService, + @IHoverService hoverService: IHoverService, + @IContextMenuService contextMenuService: IContextMenuService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService, + @IAuthenticationService authenticationService: IAuthenticationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, + @IKeybindingService keybindingService: IKeybindingService, + @ISecretStorageService secretStorageService: ISecretStorageService, + @ILogService logService: ILogService, + @IActivityService activityService: IActivityService, + @IInstantiationService instantiationService: IInstantiationService + ) { + super(() => [], { + colors: theme => ({ + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + }), + hoverOptions, + compact: true, + }, undefined, undefined, actions => actions, themeService, lifecycleService, hoverService, contextMenuService, menuService, contextKeyService, authenticationService, environmentService, productService, configurationService, keybindingService, secretStorageService, logService, activityService, instantiationService); } } -class SwitchSideBarViewAction extends Action2 { +export class SimpleGlobalActivityActionViewItem extends GlobalActivityActionViewItem { constructor( - desc: Readonly, - private readonly offset: number + hoverOptions: IActivityHoverOptions, + @IUserDataProfileService userDataProfileService: IUserDataProfileService, + @IThemeService themeService: IThemeService, + @IHoverService hoverService: IHoverService, + @IMenuService menuService: IMenuService, + @IContextMenuService contextMenuService: IContextMenuService, + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService configurationService: IConfigurationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IKeybindingService keybindingService: IKeybindingService, + @IInstantiationService instantiationService: IInstantiationService, + @IActivityService activityService: IActivityService, ) { - super(desc); - } - - async run(accessor: ServicesAccessor): Promise { - const paneCompositeService = accessor.get(IPaneCompositePartService); - - const visibleViewletIds = paneCompositeService.getVisiblePaneCompositeIds(ViewContainerLocation.Sidebar); - - const activeViewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); - if (!activeViewlet) { - return; - } - let targetViewletId: string | undefined; - for (let i = 0; i < visibleViewletIds.length; i++) { - if (visibleViewletIds[i] === activeViewlet.getId()) { - targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + this.offset) % visibleViewletIds.length]; - break; - } - } - - await paneCompositeService.openPaneComposite(targetViewletId, ViewContainerLocation.Sidebar, true); + super(() => [], { + colors: theme => ({ + badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), + badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), + }), + hoverOptions, + compact: true, + }, undefined, undefined, userDataProfileService, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService, instantiationService, activityService); } } - -registerAction2( - class PreviousSideBarViewAction extends SwitchSideBarViewAction { - constructor() { - super({ - id: 'workbench.action.previousSideBarView', - title: { value: localize('previousSideBarView', "Previous Primary Side Bar View"), original: 'Previous Primary Side Bar View' }, - category: Categories.View, - f1: true - }, -1); - } - } -); - -registerAction2( - class NextSideBarViewAction extends SwitchSideBarViewAction { - constructor() { - super({ - id: 'workbench.action.nextSideBarView', - title: { value: localize('nextSideBarView', "Next Primary Side Bar View"), original: 'Next Primary Side Bar View' }, - category: Categories.View, - f1: true - }, 1); - } - } -); - -registerAction2( - class FocusActivityBarAction extends Action2 { - constructor() { - super({ - id: 'workbench.action.focusActivityBar', - title: { value: localize('focusActivityBar', "Focus Activity Bar"), original: 'Focus Activity Bar' }, - category: Categories.View, - f1: true - }); - } - - async run(accessor: ServicesAccessor): Promise { - const layoutService = accessor.get(IWorkbenchLayoutService); - layoutService.setPartHidden(false, Parts.ACTIVITYBAR_PART); - layoutService.focusPart(Parts.ACTIVITYBAR_PART); - } - }); - -registerThemingParticipant((theme, collector) => { - - const activityBarActiveBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER); - if (activityBarActiveBorderColor) { - collector.addRule(` - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { - border-left-color: ${activityBarActiveBorderColor}; - } - `); - } - - const activityBarActiveFocusBorderColor = theme.getColor(ACTIVITY_BAR_ACTIVE_FOCUS_BORDER); - if (activityBarActiveFocusBorderColor) { - collector.addRule(` - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus::before { - visibility: hidden; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:focus .active-item-indicator:before { - visibility: visible; - border-left-color: ${activityBarActiveFocusBorderColor}; - } - `); - } - - const activityBarActiveBackgroundColor = theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND); - if (activityBarActiveBackgroundColor) { - collector.addRule(` - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator { - z-index: 0; - background-color: ${activityBarActiveBackgroundColor}; - } - `); - } - - // Styling with Outline color (e.g. high contrast theme) - const outline = theme.getColor(activeContrastBorder); - if (outline) { - collector.addRule(` - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:before { - content: ""; - position: absolute; - top: 8px; - left: 8px; - height: 32px; - width: 32px; - z-index: 1; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.profile-activity-item:before { - top: -6px; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before { - outline: 1px solid; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { - outline: 1px dashed; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before { - border-left-color: ${outline}; - } - - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:hover:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked:hover:before, - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover:before { - outline-color: ${outline}; - } - `); - } - - // Styling without outline color - else { - const focusBorderColor = theme.getColor(focusBorder); - if (focusBorderColor) { - collector.addRule(` - .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .active-item-indicator:before { - border-left-color: ${focusBorderColor}; - } - `); - } - } -}); 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 7f304713c..5960dfe27 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 @@ -362,6 +362,7 @@ } /* Layout Controls */ +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container, .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .layout-controls-container { display: none; padding-right: 2px; @@ -372,23 +373,89 @@ z-index: 2500; -webkit-app-region: no-drag; height: 100%; - margin-left: auto; min-width: 28px; } +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .layout-controls-container { + margin-left: auto; +} + +.monaco-workbench.mac:not(.web) .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container, .monaco-workbench.mac:not(.web) .part.titlebar > .titlebar-container > .titlebar-right > .layout-controls-container { right: 8px; } +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container:not(.has-no-actions), .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .layout-controls-container.show-layout-control { display: flex; justify-content: center; } +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .codicon, .monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .layout-controls-container .codicon { color: inherit; } +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item { + display: flex; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .badge { + margin-left: 8px; + display: flex; + align-items: center; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge { + margin-left: 0px; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .badge .badge-content { + padding: 3px 5px; + border-radius: 11px; + font-size: 9px; + min-width: 11px; + height: 16px; + line-height: 11px; + font-weight: normal; + text-align: center; + display: inline-block; + box-sizing: border-box; + position: relative; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact { + position: absolute; + top: 0; + bottom: 0; + margin: auto; + left: 0; + overflow: hidden; + width: 100%; + height: 100%; + z-index: 2; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content::before { + mask-size: 12px; + -webkit-mask-size: 12px; + top: 2px; +} + +.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content { + position: absolute; + top: 10px; + right: 0px; + font-size: 9px; + font-weight: 600; + min-width: 12px; + height: 12px; + line-height: 12px; + padding: 0 2px; + border-radius: 16px; + text-align: center; +} + .monaco-workbench .part.titlebar .window-controls-container .window-icon { color: var(--vscode-titleBar-activeForeground); } @@ -398,8 +465,17 @@ } /* below codes are changed by github1s */ -.monaco-workbench .activitybar > .content > .home-bar > .monaco-action-bar { +.monaco-workbench .activitybar > .content > .home-bar { + opacity: 1; height: 48px; + cursor: pointer; + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: 50% 50%; + -webkit-mask-size: 50% 50%; + mask-position: 50% 50%; + -webkit-mask-position: 50% 50%; + background-color: var(--vscode-activityBar-foreground); } .monaco-workbench .activitybar > .content > .home-bar.home-bar-clickable:hover { @@ -409,15 +485,4 @@ .monaco-workbench .activitybar > .content > .home-bar.home-bar-clickable:active { opacity: 0.4; } - -.monaco-workbench .activitybar > .content > .home-bar .home-bar-custom-icon { - opacity: 1 !important; - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: 50% 50%; - -webkit-mask-size: 50% 50%; - mask-position: 50% 50%; - -webkit-mask-position: 50% 50%; - background-color: var(--vscode-activityBar-foreground); -} /* above codes are changed by github1s */ diff --git a/vscode-web/src/vs/workbench/browser/web.main.ts b/vscode-web/src/vs/workbench/browser/web.main.ts index 569a515a2..3647c78b5 100644 --- a/vscode-web/src/vs/workbench/browser/web.main.ts +++ b/vscode-web/src/vs/workbench/browser/web.main.ts @@ -20,7 +20,7 @@ import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteA import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService'; import { IRemoteAuthorityResolverService, RemoteConnectionType } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IWorkbenchFileService } from 'vs/workbench/services/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas, connectionTokenCookieName } from 'vs/base/common/network'; import { IAnyWorkspaceIdentifier, IWorkspaceContextService, UNKNOWN_EMPTY_WINDOW_WORKSPACE, isTemporaryWorkspace, isWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; @@ -261,7 +261,7 @@ export class BrowserMain extends Disposable { // Files const fileLogger = new BufferLogger(); const fileService = this._register(new FileService(fileLogger)); - serviceCollection.set(IWorkbenchFileService, fileService); + serviceCollection.set(IFileService, fileService); // Logger const loggerService = new FileLoggerService(getLogLevel(environmentService), logsPath, fileService); @@ -429,7 +429,8 @@ export class BrowserMain extends Disposable { } } - private async registerIndexedDBFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IWorkbenchFileService, logService: ILogService, loggerService: ILoggerService, logsPath: URI): Promise { + private async registerIndexedDBFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService, loggerService: ILoggerService, logsPath: URI): Promise { + // IndexedDB is used for logging and user data let indexedDB: IndexedDB | undefined; const userDataStore = 'vscode-userdata-store'; @@ -577,7 +578,7 @@ export class BrowserMain extends Disposable { if (this.configuration.workspaceProvider) { workspace = this.configuration.workspaceProvider.workspace; } - + /* below codes are changed by github1s */ const id = window?.vscodeWeb?.workspaceId; diff --git a/vscode-web/src/vs/workbench/services/editor/browser/editorResolverService.ts b/vscode-web/src/vs/workbench/services/editor/browser/editorResolverService.ts index e00acf8e8..f0f9c77a3 100644 --- a/vscode-web/src/vs/workbench/services/editor/browser/editorResolverService.ts +++ b/vscode-web/src/vs/workbench/services/editor/browser/editorResolverService.ts @@ -265,13 +265,13 @@ export class EditorResolverService extends Disposable implements IEditorResolver private getAllUserAssociations(): EditorAssociations { const inspectedEditorAssociations = this.configurationService.inspect<{ [fileNamePattern: string]: string }>(editorsAssociationsSettingId) || {}; - /* below codes are changed by github1s */ + /* below codes are changed by github1s */ const defaultAssociations = inspectedEditorAssociations.defaultValue ?? {}; const workspaceAssociations = inspectedEditorAssociations.workspaceValue ?? {}; const userAssociations = inspectedEditorAssociations.userValue ?? {}; const rawAssociations: { [fileNamePattern: string]: string } = { ...workspaceAssociations }; // We want to apply the default associations and user associations on top of the workspace associations but ignore duplicate keys. - /* above codes are changed by github1s */ + /* above codes are changed by github1s */ for (const [key, value] of Object.entries({ ...defaultAssociations, ...userAssociations })) { if (rawAssociations[key] === undefined) { rawAssociations[key] = value; diff --git a/vscode-web/src/vs/workbench/services/textfile/browser/textFileService.ts b/vscode-web/src/vs/workbench/services/textfile/browser/textFileService.ts index 41b05e651..830713fe6 100644 --- a/vscode-web/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/vscode-web/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -45,9 +45,6 @@ import { Codicon } from 'vs/base/common/codicons'; import { listErrorForeground } from 'vs/platform/theme/common/colorRegistry'; import { firstOrDefault } from 'vs/base/common/arrays'; -/** - * The workbench file service implementation implements the raw file service spec and adds additional methods on top. - */ export abstract class AbstractTextFileService extends Disposable implements ITextFileService { declare readonly _serviceBrand: undefined; @@ -372,6 +369,16 @@ export abstract class AbstractTextFileService extends Disposable implements ITex return; // user canceled } + // Ensure target is not marked as readonly and prompt otherwise + if (this.filesConfigurationService.isReadonly(target)) { + const confirmed = await this.confirmMakeWriteable(target); + if (!confirmed) { + return; + } else { + this.filesConfigurationService.updateReadonly(target, false); + } + } + // Just save if target is same as models own resource if (isEqual(source, target)) { return this.save(source, { ...options, force: true /* force to save, even if not dirty (https://github.com/microsoft/vscode/issues/99619) */ }); @@ -564,13 +571,24 @@ export abstract class AbstractTextFileService extends Disposable implements ITex const { confirmed } = await this.dialogService.confirm({ type: 'warning', message: localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), - detail: localize('irreversible', "A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.", basename(resource), basename(dirname(resource))), + detail: localize('overwriteIrreversible', "A file or folder with the name '{0}' already exists in the folder '{1}'. Replacing it will overwrite its current contents.", basename(resource), basename(dirname(resource))), primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), }); return confirmed; } + private async confirmMakeWriteable(resource: URI): Promise { + const { confirmed } = await this.dialogService.confirm({ + type: 'warning', + message: localize('confirmMakeWriteable', "'{0}' is marked as read-only. Do you want to save anyway?", basename(resource)), + detail: localize('confirmMakeWriteableDetail', "Paths can be configured as read-only via settings."), + primaryButton: localize({ key: 'makeWriteableButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Save Anyway") + }); + + return confirmed; + } + private async suggestSavePath(resource: URI): Promise { // Just take the resource as is if the file service can handle it diff --git a/vscode-web/yarn.lock b/vscode-web/yarn.lock index a0dee5ff4..598c13b58 100644 --- a/vscode-web/yarn.lock +++ b/vscode-web/yarn.lock @@ -517,37 +517,37 @@ which@^1.2.9: dependencies: isexe "^2.0.0" -xterm-addon-canvas@0.5.0-beta.22: - version "0.5.0-beta.22" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.22.tgz#513f0c2b7cf96073f47627b27e8965c1b1a22431" - integrity sha512-9F6ZI0DMRgffVfHkLkDwl5n8VscvCaV10tWI3skXOX7Y7Aws6OEeglkOPoU3IllofCU792kHKM4pPoToUxTltg== - -xterm-addon-image@0.6.0-beta.14: - version "0.6.0-beta.14" - resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.14.tgz#75fc3f824123183a4bbb5306e22f8b2c6966b0a6" - integrity sha512-D5Gh5JTKhHaPt1KwQNf6diF37KA4eToJw3XId1wy62tWmSqfq+QflhOGTfd+SnSQYCktU05ETzM+0tncIU62pQ== - -xterm-addon-search@0.13.0-beta.20: - version "0.13.0-beta.20" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.20.tgz#8ddd0513e2a70fcefa325722100d2e1bfaf3b9cb" - integrity sha512-wrx6187cJ1UenGL6ZeYv3jFvRPhhENTfbC+Hv1Fnww8LmsKhcj+0+Pm6yInNjX/9hNVsNzdqKyqNeEMoykyoyA== - -xterm-addon-serialize@0.11.0-beta.20: - version "0.11.0-beta.20" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.20.tgz#e879b34d214761403f1081833f9221c6903bf0c3" - integrity sha512-OXnC1SATaz7kEFjFWhyv9MJaXi8yHdPjazpGLNi11h33CRTKtCQiqqPBHU87dztnXmpEX6Jw0/jr3zlyXuAmnw== - -xterm-addon-unicode11@0.6.0-beta.12: - version "0.6.0-beta.12" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0-beta.12.tgz#ac6df9d635325dc692e4c602e74a2fc27a09405c" - integrity sha512-9wWWf/5nFafYgq0pn9EgAWnXaXGleVxfjNOqavpLRYFv0nw42QbaYyGvnGcxyYHM5Aqx/8rYE/DDVWZBqQZdYA== - -xterm-addon-webgl@0.16.0-beta.30: - version "0.16.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.30.tgz#820d5c65f868b14ec4177bfb8a294931a53616bf" - integrity sha512-39qPHPFmNENxcHf8/CzGHS6wzKMMegoRkHB1+scqtBhSxFaD8tX5Ye33HZIEdQ9nXe9xtr4FWVp77T+n9hdrew== - -xterm@5.2.0-beta.30: - version "5.2.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.2.0-beta.30.tgz#6f50796d1652a61b30eeed7fa2bdd9c485a7d8ee" - integrity sha512-l1YBwMnakKXd638oxbzEg9Y1sWqxcrm/q7i5gBuWaK8N7Tq1NvF51FCamxXtfdL4dostgw8WoM+/6KRlL53t6A== +xterm-addon-canvas@0.6.0-beta.32: + version "0.6.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9" + integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w== + +xterm-addon-image@0.6.0-beta.21: + version "0.6.0-beta.21" + resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" + integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== + +xterm-addon-search@0.14.0-beta.31: + version "0.14.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274" + integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg== + +xterm-addon-serialize@0.12.0-beta.31: + version "0.12.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c" + integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw== + +xterm-addon-unicode11@0.7.0-beta.31: + version "0.7.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3" + integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ== + +xterm-addon-webgl@0.17.0-beta.31: + version "0.17.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa" + integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ== + +xterm@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a" + integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA== diff --git a/yarn.lock b/yarn.lock index 6c4131438..aa6261882 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31,10 +31,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@github1s/vscode-web@0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@github1s/vscode-web/-/vscode-web-0.14.0.tgz#a17761b468e6bd4fe6ad10952faab45d300e1bcc" - integrity sha512-8OUnxC77eD0iauRilEomlK2rduTzT0fK53J2R7ribHKTYqB+k6VWbpqF9QhZEc1Rw+0cHu2HShlgdmgOcIqObw== +"@github1s/vscode-web@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@github1s/vscode-web/-/vscode-web-0.15.0.tgz#9ad8fe6da1494edad649c07b27b12057f5b69655" + integrity sha512-lA9r2NnqJTUSaQuM7o41gYH61dSQnuC5U5oWpZAHrs+65bV/EFVfKn8LCT9t8g9kcj80xRSipvSUfktXccji/Q== dependencies: "@vscode/iconv-lite-umd" "0.7.0" "@vscode/vscode-languagedetection" "1.0.21" @@ -42,13 +42,13 @@ tas-client-umd "0.1.8" vscode-oniguruma "1.7.0" vscode-textmate "9.0.0" - xterm "5.2.0-beta.30" - xterm-addon-canvas "0.5.0-beta.22" - xterm-addon-image "0.6.0-beta.14" - xterm-addon-search "0.13.0-beta.20" - xterm-addon-serialize "0.11.0-beta.20" - xterm-addon-unicode11 "0.6.0-beta.12" - xterm-addon-webgl "0.16.0-beta.30" + xterm "5.4.0-beta.32" + xterm-addon-canvas "0.6.0-beta.32" + xterm-addon-image "0.6.0-beta.21" + xterm-addon-search "0.14.0-beta.31" + xterm-addon-serialize "0.12.0-beta.31" + xterm-addon-unicode11 "0.7.0-beta.31" + xterm-addon-webgl "0.17.0-beta.31" "@hapi/hoek@^9.0.0": version "9.3.0" @@ -4302,40 +4302,40 @@ ws@^8.4.2: resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== -xterm-addon-canvas@0.5.0-beta.22: - version "0.5.0-beta.22" - resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.22.tgz#513f0c2b7cf96073f47627b27e8965c1b1a22431" - integrity sha512-9F6ZI0DMRgffVfHkLkDwl5n8VscvCaV10tWI3skXOX7Y7Aws6OEeglkOPoU3IllofCU792kHKM4pPoToUxTltg== - -xterm-addon-image@0.6.0-beta.14: - version "0.6.0-beta.14" - resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.14.tgz#75fc3f824123183a4bbb5306e22f8b2c6966b0a6" - integrity sha512-D5Gh5JTKhHaPt1KwQNf6diF37KA4eToJw3XId1wy62tWmSqfq+QflhOGTfd+SnSQYCktU05ETzM+0tncIU62pQ== - -xterm-addon-search@0.13.0-beta.20: - version "0.13.0-beta.20" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.20.tgz#8ddd0513e2a70fcefa325722100d2e1bfaf3b9cb" - integrity sha512-wrx6187cJ1UenGL6ZeYv3jFvRPhhENTfbC+Hv1Fnww8LmsKhcj+0+Pm6yInNjX/9hNVsNzdqKyqNeEMoykyoyA== - -xterm-addon-serialize@0.11.0-beta.20: - version "0.11.0-beta.20" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.20.tgz#e879b34d214761403f1081833f9221c6903bf0c3" - integrity sha512-OXnC1SATaz7kEFjFWhyv9MJaXi8yHdPjazpGLNi11h33CRTKtCQiqqPBHU87dztnXmpEX6Jw0/jr3zlyXuAmnw== - -xterm-addon-unicode11@0.6.0-beta.12: - version "0.6.0-beta.12" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0-beta.12.tgz#ac6df9d635325dc692e4c602e74a2fc27a09405c" - integrity sha512-9wWWf/5nFafYgq0pn9EgAWnXaXGleVxfjNOqavpLRYFv0nw42QbaYyGvnGcxyYHM5Aqx/8rYE/DDVWZBqQZdYA== - -xterm-addon-webgl@0.16.0-beta.30: - version "0.16.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.30.tgz#820d5c65f868b14ec4177bfb8a294931a53616bf" - integrity sha512-39qPHPFmNENxcHf8/CzGHS6wzKMMegoRkHB1+scqtBhSxFaD8tX5Ye33HZIEdQ9nXe9xtr4FWVp77T+n9hdrew== - -xterm@5.2.0-beta.30: - version "5.2.0-beta.30" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.2.0-beta.30.tgz#6f50796d1652a61b30eeed7fa2bdd9c485a7d8ee" - integrity sha512-l1YBwMnakKXd638oxbzEg9Y1sWqxcrm/q7i5gBuWaK8N7Tq1NvF51FCamxXtfdL4dostgw8WoM+/6KRlL53t6A== +xterm-addon-canvas@0.6.0-beta.32: + version "0.6.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9" + integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w== + +xterm-addon-image@0.6.0-beta.21: + version "0.6.0-beta.21" + resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac" + integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ== + +xterm-addon-search@0.14.0-beta.31: + version "0.14.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274" + integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg== + +xterm-addon-serialize@0.12.0-beta.31: + version "0.12.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c" + integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw== + +xterm-addon-unicode11@0.7.0-beta.31: + version "0.7.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3" + integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ== + +xterm-addon-webgl@0.17.0-beta.31: + version "0.17.0-beta.31" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa" + integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ== + +xterm@5.4.0-beta.32: + version "5.4.0-beta.32" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a" + integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA== y18n@^5.0.5: version "5.0.8"