Closed
Description
Verification steps:
- Use the "Open Merge Editor State From JSON" command to load the attached JSON
- Use the menu behind "..." to toggle base
- Verify base is shown
{
"languageId": "typescript",
"base": "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IStatusbarEntry, ShowTooltipCommand } from 'vs/workbench/services/statusbar/browser/statusbar';\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\nimport { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\nimport { isThemeColor } from 'vs/editor/common/editorCommon';\nimport { addDisposableListener, EventType, hide, show, append, EventHelper } from 'vs/base/browser/dom';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { Command } from 'vs/editor/common/languages';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { spinningLoading, syncing } from 'vs/platform/theme/common/iconRegistry';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\n\nexport class StatusbarEntryItem extends Disposable {\n\n\tprivate readonly label: StatusBarCodiconLabel;\n\n\tprivate entry: IStatusbarEntry | undefined = undefined;\n\n\tprivate readonly foregroundListener = this._register(new MutableDisposable());\n\tprivate readonly backgroundListener = this._register(new MutableDisposable());\n\n\tprivate readonly commandMouseListener = this._register(new MutableDisposable());\n\tprivate readonly commandTouchListener = this._register(new MutableDisposable());\n\tprivate readonly commandKeyboardListener = this._register(new MutableDisposable());\n\n\tprivate hover: ICustomHover | undefined = undefined;\n\n\treadonly labelContainer: HTMLElement;\n\n\tget name(): string {\n\t\treturn assertIsDefined(this.entry).name;\n\t}\n\n\tget hasCommand(): boolean {\n\t\treturn typeof this.entry?.command !== 'undefined';\n\t}\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tentry: IStatusbarEntry,\n\t\tprivate readonly hoverDelegate: IHoverDelegate,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@INotificationService private readonly notificationService: INotificationService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IThemeService private readonly themeService: IThemeService\n\t) {\n\t\tsuper();\n\n\t\t// Label Container\n\t\tthis.labelContainer = document.createElement('a');\n\t\tthis.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.\n\t\tthis.labelContainer.setAttribute('role', 'button');\n\t\tthis._register(Gesture.addTarget(this.labelContainer)); // enable touch\n\n\t\t// Label (with support for progress)\n\t\tthis.label = new StatusBarCodiconLabel(this.labelContainer);\n\n\t\t// Add to parent\n\t\tthis.container.appendChild(this.labelContainer);\n\n\t\tthis.update(entry);\n\t}\n\n\tupdate(entry: IStatusbarEntry): void {\n\n\t\t// Update: Progress\n\t\tthis.label.showProgress = entry.showProgress ?? false;\n\n\t\t// Update: Text\n\t\tif (!this.entry || entry.text !== this.entry.text) {\n\t\t\tthis.label.text = entry.text;\n\n\t\t\tif (entry.text) {\n\t\t\t\tshow(this.labelContainer);\n\t\t\t} else {\n\t\t\t\thide(this.labelContainer);\n\t\t\t}\n\t\t}\n\n\t\t// Update: ARIA label\n\t\t//\n\t\t// Set the aria label on both elements so screen readers would read\n\t\t// the correct thing without duplication #96210\n\n\t\tif (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {\n\t\t\tthis.container.setAttribute('aria-label', entry.ariaLabel);\n\t\t\tthis.labelContainer.setAttribute('aria-label', entry.ariaLabel);\n\t\t}\n\n\t\tif (!this.entry || entry.role !== this.entry.role) {\n\t\t\tthis.labelContainer.setAttribute('role', entry.role || 'button');\n\t\t}\n\n\t\t// Update: Hover\n\t\tif (!this.entry || !this.isEqualTooltip(this.entry, entry)) {\n\t\t\tconst hoverContents = isMarkdownString(entry.tooltip) ? { markdown: entry.tooltip, markdownNotSupportedFallback: undefined } : entry.tooltip;\n\t\t\tif (this.hover) {\n\t\t\t\tthis.hover.update(hoverContents);\n\t\t\t} else {\n\t\t\t\tthis.hover = this._register(setupCustomHover(this.hoverDelegate, this.container, hoverContents));\n\t\t\t}\n\t\t}\n\n\t\t// Update: Command\n\t\tif (!this.entry || entry.command !== this.entry.command) {\n\t\t\tthis.commandMouseListener.clear();\n\t\t\tthis.commandTouchListener.clear();\n\t\t\tthis.commandKeyboardListener.clear();\n\n\t\t\tconst command = entry.command;\n\t\t\tif (command && (command !== ShowTooltipCommand || this.hover) /* \"Show Hover\" is only valid when we have a hover */) {\n\t\t\t\tthis.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));\n\t\t\t\tthis.commandTouchListener.value = addDisposableListener(this.labelContainer, TouchEventType.Tap, () => this.executeCommand(command));\n\t\t\t\tthis.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\t\tif (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tthis.executeCommand(command);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tthis.labelContainer.classList.remove('disabled');\n\t\t\t} else {\n\t\t\t\tthis.labelContainer.classList.add('disabled');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Beak\n\t\tif (!this.entry || entry.showBeak !== this.entry.showBeak) {\n\t\t\tif (entry.showBeak) {\n\t\t\t\tthis.container.classList.add('has-beak');\n\t\t\t} else {\n\t\t\t\tthis.container.classList.remove('has-beak');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Foreground\n\t\tif (!this.entry || entry.color !== this.entry.color) {\n\t\t\tthis.applyColor(this.labelContainer, entry.color);\n\t\t}\n\n\t\t// Update: Background\n\t\tif (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) {\n\t\t\tthis.container.classList.toggle('has-background-color', !!entry.backgroundColor);\n\t\t\tthis.applyColor(this.container, entry.backgroundColor, true);\n\t\t}\n\n\t\t// Remember for next round\n\t\tthis.entry = entry;\n\t}\n\n\tprivate isEqualTooltip({ tooltip }: IStatusbarEntry, { tooltip: otherTooltip }: IStatusbarEntry) {\n\t\tif (tooltip === undefined) {\n\t\t\treturn otherTooltip === undefined;\n\t\t}\n\n\t\tif (isMarkdownString(tooltip)) {\n\t\t\treturn isMarkdownString(otherTooltip) && markdownStringEqual(tooltip, otherTooltip);\n\t\t}\n\n\t\treturn tooltip === otherTooltip;\n\t}\n\n\tprivate async executeCommand(command: string | Command): Promise<void> {\n\n\t\t// Custom command from us: Show tooltip\n\t\tif (command === ShowTooltipCommand) {\n\t\t\tthis.hover?.show(true /* focus */);\n\t\t}\n\n\t\t// Any other command is going through command service\n\t\telse {\n\t\t\tconst id = typeof command === 'string' ? command : command.id;\n\t\t\tconst args = typeof command === 'string' ? [] : command.arguments ?? [];\n\n\t\t\tthis.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });\n\t\t\ttry {\n\t\t\t\tawait this.commandService.executeCommand(id, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.notificationService.error(toErrorMessage(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {\n\t\tlet colorResult: string | undefined = undefined;\n\n\t\tif (isBackground) {\n\t\t\tthis.backgroundListener.clear();\n\t\t} else {\n\t\t\tthis.foregroundListener.clear();\n\t\t}\n\n\t\tif (color) {\n\t\t\tif (isThemeColor(color)) {\n\t\t\t\tcolorResult = this.themeService.getColorTheme().getColor(color.id)?.toString();\n\n\t\t\t\tconst listener = this.themeService.onDidColorThemeChange(theme => {\n\t\t\t\t\tconst colorValue = theme.getColor(color.id)?.toString();\n\n\t\t\t\t\tif (isBackground) {\n\t\t\t\t\t\tcontainer.style.backgroundColor = colorValue ?? '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontainer.style.color = colorValue ?? '';\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (isBackground) {\n\t\t\t\t\tthis.backgroundListener.value = listener;\n\t\t\t\t} else {\n\t\t\t\t\tthis.foregroundListener.value = listener;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolorResult = color;\n\t\t\t}\n\t\t}\n\n\t\tif (isBackground) {\n\t\t\tcontainer.style.backgroundColor = colorResult ?? '';\n\t\t} else {\n\t\t\tcontainer.style.color = colorResult ?? '';\n\t\t}\n\t}\n}\n\nclass StatusBarCodiconLabel extends SimpleIconLabel {\n\n\tprivate progressCodicon = renderIcon(syncing);\n\n\tprivate currentText = '';\n\tprivate currentShowProgress = false;\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement\n\t) {\n\t\tsuper(container);\n\t}\n\n\tset showProgress(showProgress: boolean | 'syncing' | 'loading') {\n\t\tif (this.currentShowProgress !== showProgress) {\n\t\t\tthis.currentShowProgress = !!showProgress;\n\t\t\tthis.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);\n\t\t\tthis.text = this.currentText;\n\t\t}\n\t}\n\n\toverride set text(text: string) {\n\n\t\t// Progress: insert progress codicon as first element as needed\n\t\t// but keep it stable so that the animation does not reset\n\t\tif (this.currentShowProgress) {\n\n\t\t\t// Append as needed\n\t\t\tif (this.container.firstChild !== this.progressCodicon) {\n\t\t\t\tthis.container.appendChild(this.progressCodicon);\n\t\t\t}\n\n\t\t\t// Remove others\n\t\t\tfor (const node of Array.from(this.container.childNodes)) {\n\t\t\t\tif (node !== this.progressCodicon) {\n\t\t\t\t\tnode.remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have text to show, add a space to separate from progress\n\t\t\tlet textContent = text ?? '';\n\t\t\tif (textContent) {\n\t\t\t\ttextContent = ` ${textContent}`;\n\t\t\t}\n\n\t\t\t// Append new elements\n\t\t\tappend(this.container, ...renderLabelWithIcons(textContent));\n\t\t}\n\n\t\t// No Progress: no special handling\n\t\telse {\n\t\t\tsuper.text = text;\n\t\t}\n\t}\n}\n",
"input1": "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { toErrorMessage2 } from 'vs/base/common/errorMessage2';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IStatusbarEntry, ShowTooltipCommand } from 'vs/workbench/services/statusbar/browser/statusbar';\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\nimport { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\nimport { isThemeColor } from 'vs/editor/common/editorCommon';\nimport { addDisposableListener, EventType, hide, show, append, EventHelper } from 'vs/base/browser/dom';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { Command } from 'vs/editor/common/languages';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { spinningLoading, syncing } from 'vs/platform/theme/common/iconRegistry';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\n\nexport class StatusbarEntryItem extends Disposable {\n\n\tprivate readonly label: StatusBarCodiconLabel;\n\n\tprivate entry: IStatusbarEntry | undefined = undefined;\n\n\tprivate readonly foregroundListener = this._register(new MutableDisposable());\n\tprivate readonly backgroundListener = this._register(new MutableDisposable());\n\n\tprivate readonly commandMouseListener = this._register(new MutableDisposable());\n\tprivate readonly commandTouchListener = this._register(new MutableDisposable());\n\tprivate readonly commandKeyboardListener = this._register(new MutableDisposable());\n\n\tprivate hover: ICustomHover | undefined = undefined;\n\n\treadonly labelContainer: HTMLElement;\n\treadonly beakContainer: HTMLElement;\n\n\tget name(): string {\n\t\treturn assertIsDefined(this.entry).name;\n\t}\n\n\tget hasCommand(): boolean {\n\t\treturn typeof this.entry?.command !== 'undefined';\n\t}\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tentry: IStatusbarEntry,\n\t\tprivate readonly hoverDelegate: IHoverDelegate,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@INotificationService private readonly notificationService: INotificationService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IThemeService private readonly themeService: IThemeService\n\t) {\n\t\tsuper();\n\n\t\t// Label Container\n\t\tthis.labelContainer = document.createElement('a');\n\t\tthis.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.\n\t\tthis.labelContainer.setAttribute('role', 'button');\n\t\tthis._register(Gesture.addTarget(this.labelContainer)); // enable touch\n\n\t\t// Label (with support for progress)\n\t\tthis.label = new StatusBarCodiconLabel(this.labelContainer);\n\t\tthis.container.appendChild(this.labelContainer);\n\n\t\t// Beak Container\n\t\tthis.beakContainer = document.createElement('div');\n\t\tthis.beakContainer.className = 'status-bar-item-beak-container';\n\t\tthis.container.appendChild(this.beakContainer);\n\n\t\tthis.update(entry);\n\t}\n\n\tupdate(entry: IStatusbarEntry): void {\n\n\t\t// Update: Progress\n\t\tthis.label.showProgress = entry.showProgress ?? false;\n\n\t\t// Update: Text\n\t\tif (!this.entry || entry.text !== this.entry.text) {\n\t\t\tthis.label.text = entry.text;\n\n\t\t\tif (entry.text) {\n\t\t\t\tshow(this.labelContainer);\n\t\t\t} else {\n\t\t\t\thide(this.labelContainer);\n\t\t\t}\n\t\t}\n\n\t\t// Update: ARIA label\n\t\t//\n\t\t// Set the aria label on both elements so screen readers would read\n\t\t// the correct thing without duplication #96210\n\n\t\tif (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {\n\t\t\tthis.container.setAttribute('aria-label', entry.ariaLabel);\n\t\t\tthis.labelContainer.setAttribute('aria-label', entry.ariaLabel);\n\t\t}\n\n\t\tif (!this.entry || entry.role !== this.entry.role) {\n\t\t\tthis.labelContainer.setAttribute('role', entry.role || 'button');\n\t\t}\n\n\t\t// Update: Hover\n\t\tif (!this.entry || !this.isEqualTooltip(this.entry, entry)) {\n\t\t\tconst hoverContents = isMarkdownString(entry.tooltip) ? { markdown: entry.tooltip, markdownNotSupportedFallback: undefined } : entry.tooltip;\n\t\t\tif (this.hover) {\n\t\t\t\tthis.hover.update(hoverContents);\n\t\t\t} else {\n\t\t\t\tthis.hover = this._register(setupCustomHover(this.hoverDelegate, this.container, hoverContents));\n\t\t\t}\n\t\t}\n\n\t\t// Update: Command\n\t\tif (!this.entry || entry.command !== this.entry.command) {\n\t\t\tthis.commandMouseListener.clear();\n\t\t\tthis.commandTouchListener.clear();\n\t\t\tthis.commandKeyboardListener.clear();\n\n\t\t\tconst command = entry.command;\n\t\t\tif (command && (command !== ShowTooltipCommand || this.hover) /* \"Show Hover\" is only valid when we have a hover */) {\n\t\t\t\tthis.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));\n\t\t\t\tthis.commandTouchListener.value = addDisposableListener(this.labelContainer, TouchEventType.Tap, () => this.executeCommand(command));\n\t\t\t\tthis.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\t\tif (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tthis.executeCommand(command);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tthis.labelContainer.classList.remove('disabled');\n\t\t\t} else {\n\t\t\t\tthis.labelContainer.classList.add('disabled');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Beak\n\t\tif (!this.entry || entry.showBeak !== this.entry.showBeak) {\n\t\t\tif (entry.showBeak) {\n\t\t\t\tthis.container.classList.add('has-beak');\n\t\t\t} else {\n\t\t\t\tthis.container.classList.remove('has-beak');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Foreground\n\t\tif (!this.entry || entry.color !== this.entry.color) {\n\t\t\tthis.applyColor(this.labelContainer, entry.color);\n\t\t}\n\n\t\t// Update: Background\n\t\tif (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) {\n\t\t\tthis.container.classList.toggle('has-background-color', !!entry.backgroundColor);\n\t\t\tthis.applyColor(this.container, entry.backgroundColor, true);\n\t\t}\n\n\t\t// Remember for next round\n\t\tthis.entry = entry;\n\t}\n\n\tprivate isEqualTooltip({ tooltip }: IStatusbarEntry, { tooltip: otherTooltip }: IStatusbarEntry) {\n\t\tif (tooltip === undefined) {\n\t\t\treturn otherTooltip === undefined;\n\t\t}\n\n\t\tif (isMarkdownString(tooltip)) {\n\t\t\treturn isMarkdownString(otherTooltip) && markdownStringEqual(tooltip, otherTooltip);\n\t\t}\n\n\t\treturn tooltip === otherTooltip;\n\t}\n\n\tprivate async executeCommand(command: string | Command): Promise<void> {\n\n\t\t// Custom command from us: Show tooltip\n\t\tif (command === ShowTooltipCommand) {\n\t\t\tthis.hover?.show(true /* focus */);\n\t\t}\n\n\t\t// Any other command is going through command service\n\t\telse {\n\t\t\tconst id = typeof command === 'string' ? command : command.id;\n\t\t\tconst args = typeof command === 'string' ? [] : command.arguments ?? [];\n\n\t\t\tthis.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });\n\t\t\ttry {\n\t\t\t\tawait this.commandService.executeCommand(id, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.notificationService.error(toErrorMessage(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {\n\t\tlet colorResult: string | undefined = undefined;\n\n\t\tif (isBackground) {\n\t\t\tthis.backgroundListener.clear();\n\t\t} else {\n\t\t\tthis.foregroundListener.clear();\n\t\t}\n\n\t\tif (color) {\n\t\t\tif (isThemeColor(color)) {\n\t\t\t\tcolorResult = this.themeService.getColorTheme().getColor(color.id)?.toString();\n\n\t\t\t\tconst listener = this.themeService.onDidColorThemeChange(theme => {\n\t\t\t\t\tconst colorValue = theme.getColor(color.id)?.toString();\n\n\t\t\t\t\tif (isBackground) {\n\t\t\t\t\t\tcontainer.style.backgroundColor = colorValue ?? '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontainer.style.color = colorValue ?? '';\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (isBackground) {\n\t\t\t\t\tthis.backgroundListener.value = listener;\n\t\t\t\t} else {\n\t\t\t\t\tthis.foregroundListener.value = listener;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolorResult = color;\n\t\t\t}\n\t\t}\n\n\t\tif (isBackground) {\n\t\t\tcontainer.style.backgroundColor = colorResult ?? '';\n\t\t} else {\n\t\t\tcontainer.style.color = colorResult ?? '';\n\t\t}\n\t}\n}\n\nclass StatusBarCodiconLabel extends SimpleIconLabel {\n\n\tprivate progressCodicon = renderIcon(syncing);\n\n\tprivate currentText = '';\n\tprivate currentShowProgress = false;\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement\n\t) {\n\t\tsuper(container);\n\t}\n\n\tset showProgress(showProgress: boolean | 'syncing' | 'loading') {\n\t\tif (this.currentShowProgress !== showProgress) {\n\t\t\tthis.currentShowProgress = !!showProgress;\n\t\t\tthis.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);\n\t\t\tthis.text = this.currentText;\n\t\t}\n\t}\n\n\toverride set text(text: string) {\n\n\t\t// Progress: insert progress codicon as first element as needed\n\t\t// but keep it stable so that the animation does not reset\n\t\tif (this.currentShowProgress) {\n\n\t\t\t// Append as needed\n\t\t\tif (this.container.firstChild !== this.progressCodicon) {\n\t\t\t\tthis.container.appendChild(this.progressCodicon);\n\t\t\t}\n\n\t\t\t// Remove others\n\t\t\tfor (const node of Array.from(this.container.childNodes)) {\n\t\t\t\tif (node !== this.progressCodicon) {\n\t\t\t\t\tnode.remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have text to show, add a space to separate from progress\n\t\t\tlet textContent = text ?? '';\n\t\t\tif (textContent) {\n\t\t\t\ttextContent = ` ${textContent}`;\n\t\t\t}\n\n\t\t\t// Append new elements\n\t\t\tappend(this.container, ...renderLabelWithIcons(textContent));\n\t\t}\n\n\t\t// No Progress: no special handling\n\t\telse {\n\t\t\tsuper.text = text;\n\t\t}\n\t}\n}\n",
"input2": "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IStatusbarEntry, ShowTooltipCommand } from 'vs/workbench/services/statusbar/browser/statusbar';\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\nimport { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\nimport { isThemeColor } from 'vs/editor/common/editorCommon';\nimport { addDisposableListener, EventType, hide, show, append, EventHelper } from 'vs/base/browser/dom';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { Command } from 'vs/editor/common/languages';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { spinningLoading, syncing } from 'vs/platform/theme/common/iconRegistry';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\n\nexport class StatusbarEntryItem extends Disposable {\n\n\tprivate readonly label: StatusBarCodiconLabel;\n\n\tprivate entry: IStatusbarEntry | undefined = undefined;\n\n\tprivate readonly foregroundListener = this._register(new MutableDisposable());\n\tprivate readonly backgroundListener = this._register(new MutableDisposable());\n\n\tprivate readonly commandMouseListener = this._register(new MutableDisposable());\n\tprivate readonly commandTouchListener = this._register(new MutableDisposable());\n\tprivate readonly commandKeyboardListener = this._register(new MutableDisposable());\n\n\tprivate hover: ICustomHover | undefined = undefined;\n\n\treadonly labelContainer: HTMLElement;\n\treadonly beakContainer: HTMLElement;\n\n\tget name(): string {\n\t\treturn assertIsDefined(this.entry).name;\n\t}\n\n\tget hasCommand(): boolean {\n\t\treturn typeof this.entry?.command !== 'undefined';\n\t}\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tentry: IStatusbarEntry,\n\t\tprivate readonly hoverDelegate: IHoverDelegate,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@INotificationService private readonly notificationService: INotificationService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IThemeService private readonly themeService: IThemeService\n\t) {\n\t\tsuper();\n\n\t\t// Label Container\n\t\tthis.labelContainer = document.createElement('a');\n\t\tthis.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.\n\t\tthis.labelContainer.setAttribute('role', 'button');\n\t\tthis._register(Gesture.addTarget(this.labelContainer)); // enable touch\n\n\t\t// Label (with support for progress)\n\t\tthis.label = new StatusBarCodiconLabel(this.labelContainer);\n\n\t\t// Add to parent\n\t\tthis.container.appendChild(this.labelContainer);\n\n\t\t// Beak Container\n\t\tthis.beakContainer = document.createElement('div');\n\t\tthis.beakContainer.className = 'status-bar-beak-container';\n\n\t\t// Add to parent\n\t\tthis.container.appendChild(this.beakContainer);\n\n\t\tthis.update(entry);\n\t}\n\n\tupdate(entry: IStatusbarEntry): void {\n\n\t\t// Update: Progress\n\t\tthis.label.showProgress = entry.showProgress ?? false;\n\n\t\t// Update: Text\n\t\tif (!this.entry || entry.text !== this.entry.text) {\n\t\t\tthis.label.text = entry.text;\n\n\t\t\tif (entry.text) {\n\t\t\t\tshow(this.labelContainer);\n\t\t\t} else {\n\t\t\t\thide(this.labelContainer);\n\t\t\t}\n\t\t}\n\n\t\t// Update: ARIA label\n\t\t//\n\t\t// Set the aria label on both elements so screen readers would read\n\t\t// the correct thing without duplication #96210\n\n\t\tif (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {\n\t\t\tthis.container.setAttribute('aria-label', entry.ariaLabel);\n\t\t\tthis.labelContainer.setAttribute('aria-label', entry.ariaLabel);\n\t\t}\n\n\t\tif (!this.entry || entry.role !== this.entry.role) {\n\t\t\tthis.labelContainer.setAttribute('role', entry.role || 'button');\n\t\t}\n\n\t\t// Update: Hover\n\t\tif (!this.entry || !this.isEqualTooltip(this.entry, entry)) {\n\t\t\tconst hoverContents = isMarkdownString(entry.tooltip) ? { markdown: entry.tooltip, markdownNotSupportedFallback: undefined } : entry.tooltip;\n\t\t\tif (this.hover) {\n\t\t\t\tthis.hover.update(hoverContents);\n\t\t\t} else {\n\t\t\t\tthis.hover = this._register(setupCustomHover(this.hoverDelegate, this.container, hoverContents));\n\t\t\t}\n\t\t}\n\n\t\t// Update: Command\n\t\tif (!this.entry || entry.command !== this.entry.command) {\n\t\t\tthis.commandMouseListener.clear();\n\t\t\tthis.commandTouchListener.clear();\n\t\t\tthis.commandKeyboardListener.clear();\n\n\t\t\tconst command = entry.command;\n\t\t\tif (command && (command !== ShowTooltipCommand || this.hover) /* \"Show Hover\" is only valid when we have a hover */) {\n\t\t\t\tthis.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));\n\t\t\t\tthis.commandTouchListener.value = addDisposableListener(this.labelContainer, TouchEventType.Tap, () => this.executeCommand(command));\n\t\t\t\tthis.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\t\tif (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tthis.executeCommand(command);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tthis.labelContainer.classList.remove('disabled');\n\t\t\t} else {\n\t\t\t\tthis.labelContainer.classList.add('disabled');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Beak\n\t\tif (!this.entry || entry.showBeak !== this.entry.showBeak) {\n\t\t\tif (entry.showBeak) {\n\t\t\t\tthis.container.classList.add('has-beak');\n\t\t\t} else {\n\t\t\t\tthis.container.classList.remove('has-beak');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Foreground\n\t\tif (!this.entry || entry.color !== this.entry.color) {\n\t\t\tthis.applyColor(this.labelContainer, entry.color);\n\t\t}\n\n\t\t// Update: Background\n\t\tif (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) {\n\t\t\tthis.container.classList.toggle('has-background-color', !!entry.backgroundColor);\n\t\t\tthis.applyColor(this.container, entry.backgroundColor, true);\n\t\t}\n\n\t\t// Remember for next round\n\t\tthis.entry = entry;\n\t}\n\n\tprivate isEqualTooltip({ tooltip }: IStatusbarEntry, { tooltip: otherTooltip }: IStatusbarEntry) {\n\t\tif (tooltip === undefined) {\n\t\t\treturn otherTooltip === undefined;\n\t\t}\n\n\t\tif (isMarkdownString(tooltip)) {\n\t\t\treturn isMarkdownString(otherTooltip) && markdownStringEqual(tooltip, otherTooltip);\n\t\t}\n\n\t\treturn tooltip === otherTooltip;\n\t}\n\n\tprivate async executeCommand(command: string | Command): Promise<void> {\n\n\t\t// Custom command from us: Show tooltip\n\t\tif (command === ShowTooltipCommand) {\n\t\t\tthis.hover?.show(true /* focus */);\n\t\t}\n\n\t\t// Any other command is going through command service\n\t\telse {\n\t\t\tconst id = typeof command === 'string' ? command : command.id;\n\t\t\tconst args = typeof command === 'string' ? [] : command.arguments ?? [];\n\n\t\t\tthis.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });\n\t\t\ttry {\n\t\t\t\tawait this.commandService.executeCommand(id, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.notificationService.error(toErrorMessage(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {\n\t\tlet colorResult: string | undefined = undefined;\n\n\t\tif (isBackground) {\n\t\t\tthis.backgroundListener.clear();\n\t\t} else {\n\t\t\tthis.foregroundListener.clear();\n\t\t}\n\n\t\tif (color) {\n\t\t\tif (isThemeColor(color)) {\n\t\t\t\tcolorResult = this.themeService.getColorTheme().getColor(color.id)?.toString();\n\n\t\t\t\tconst listener = this.themeService.onDidColorThemeChange(theme => {\n\t\t\t\t\tconst colorValue = theme.getColor(color.id)?.toString();\n\n\t\t\t\t\tif (isBackground) {\n\t\t\t\t\t\tcontainer.style.backgroundColor = colorValue ?? '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontainer.style.color = colorValue ?? '';\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (isBackground) {\n\t\t\t\t\tthis.backgroundListener.value = listener;\n\t\t\t\t} else {\n\t\t\t\t\tthis.foregroundListener.value = listener;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolorResult = color;\n\t\t\t}\n\t\t}\n\n\t\tif (isBackground) {\n\t\t\tcontainer.style.backgroundColor = colorResult ?? '';\n\t\t} else {\n\t\t\tcontainer.style.color = colorResult ?? '';\n\t\t}\n\t}\n}\n\nclass StatusBarCodiconLabel extends SimpleIconLabel {\n\n\tprivate progressCodicon = renderIcon(syncing);\n\n\tprivate currentText = '';\n\tprivate currentShowProgress = false;\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement\n\t) {\n\t\tsuper(container);\n\t}\n\n\tset showProgress(showProgress: boolean | 'syncing' | 'loading') {\n\t\tif (this.currentShowProgress !== showProgress) {\n\t\t\tthis.currentShowProgress = !!showProgress;\n\t\t\tthis.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);\n\t\t\tthis.text = this.currentText;\n\t\t}\n\t}\n\n\toverride set text(text: string) {\n\n\t\t// Progress: insert progress codicon as first element as needed\n\t\t// but keep it stable so that the animation does not reset\n\t\tif (this.currentShowProgress) {\n\n\t\t\t// Append as needed\n\t\t\tif (this.container.firstChild !== this.progressCodicon) {\n\t\t\t\tthis.container.appendChild(this.progressCodicon);\n\t\t\t}\n\n\t\t\t// Remove others\n\t\t\tfor (const node of Array.from(this.container.childNodes)) {\n\t\t\t\tif (node !== this.progressCodicon) {\n\t\t\t\t\tnode.remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have text to show, add a space to separate from progress\n\t\t\tlet textContent = text ?? '';\n\t\t\tif (textContent) {\n\t\t\t\ttextContent = ` ${textContent}`;\n\t\t\t}\n\n\t\t\t// Append new elements\n\t\t\tappend(this.container, ...renderLabelWithIcons(textContent));\n\t\t}\n\n\t\t// No Progress: no special handling\n\t\telse {\n\t\t\tsuper.text = text;\n\t\t}\n\t}\n}\n",
"result": "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { toErrorMessage2 } from 'vs/base/common/errorMessage2';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IStatusbarEntry, ShowTooltipCommand } from 'vs/workbench/services/statusbar/browser/statusbar';\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\nimport { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\nimport { isThemeColor } from 'vs/editor/common/editorCommon';\nimport { addDisposableListener, EventType, hide, show, append, EventHelper } from 'vs/base/browser/dom';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { Command } from 'vs/editor/common/languages';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { spinningLoading, syncing } from 'vs/platform/theme/common/iconRegistry';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\n\nexport class StatusbarEntryItem extends Disposable {\n\n\tprivate readonly label: StatusBarCodiconLabel;\n\n\tprivate entry: IStatusbarEntry | undefined = undefined;\n\n\tprivate readonly foregroundListener = this._register(new MutableDisposable());\n\tprivate readonly backgroundListener = this._register(new MutableDisposable());\n\n\tprivate readonly commandMouseListener = this._register(new MutableDisposable());\n\tprivate readonly commandTouchListener = this._register(new MutableDisposable());\n\tprivate readonly commandKeyboardListener = this._register(new MutableDisposable());\n\n\tprivate hover: ICustomHover | undefined = undefined;\n\n\treadonly labelContainer: HTMLElement;\n\n\tget name(): string {\n\t\treturn assertIsDefined(this.entry).name;\n\t}\n\n\tget hasCommand(): boolean {\n\t\treturn typeof this.entry?.command !== 'undefined';\n\t}\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tentry: IStatusbarEntry,\n\t\tprivate readonly hoverDelegate: IHoverDelegate,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@INotificationService private readonly notificationService: INotificationService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IThemeService private readonly themeService: IThemeService\n\t) {\n\t\tsuper();\n\n\t\t// Label Container\n\t\tthis.labelContainer = document.createElement('a');\n\t\tthis.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.\n\t\tthis.labelContainer.setAttribute('role', 'button');\n\t\tthis._register(Gesture.addTarget(this.labelContainer)); // enable touch\n\n\t\t// Label (with support for progress)\n\t\tthis.label = new StatusBarCodiconLabel(this.labelContainer);\n\t\tthis.container.appendChild(this.labelContainer);\n\n\t\tthis.update(entry);\n\t}\n\n\tupdate(entry: IStatusbarEntry): void {\n\n\t\t// Update: Progress\n\t\tthis.label.showProgress = entry.showProgress ?? false;\n\n\t\t// Update: Text\n\t\tif (!this.entry || entry.text !== this.entry.text) {\n\t\t\tthis.label.text = entry.text;\n\n\t\t\tif (entry.text) {\n\t\t\t\tshow(this.labelContainer);\n\t\t\t} else {\n\t\t\t\thide(this.labelContainer);\n\t\t\t}\n\t\t}\n\n\t\t// Update: ARIA label\n\t\t//\n\t\t// Set the aria label on both elements so screen readers would read\n\t\t// the correct thing without duplication #96210\n\n\t\tif (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {\n\t\t\tthis.container.setAttribute('aria-label', entry.ariaLabel);\n\t\t\tthis.labelContainer.setAttribute('aria-label', entry.ariaLabel);\n\t\t}\n\n\t\tif (!this.entry || entry.role !== this.entry.role) {\n\t\t\tthis.labelContainer.setAttribute('role', entry.role || 'button');\n\t\t}\n\n\t\t// Update: Hover\n\t\tif (!this.entry || !this.isEqualTooltip(this.entry, entry)) {\n\t\t\tconst hoverContents = isMarkdownString(entry.tooltip) ? { markdown: entry.tooltip, markdownNotSupportedFallback: undefined } : entry.tooltip;\n\t\t\tif (this.hover) {\n\t\t\t\tthis.hover.update(hoverContents);\n\t\t\t} else {\n\t\t\t\tthis.hover = this._register(setupCustomHover(this.hoverDelegate, this.container, hoverContents));\n\t\t\t}\n\t\t}\n\n\t\t// Update: Command\n\t\tif (!this.entry || entry.command !== this.entry.command) {\n\t\t\tthis.commandMouseListener.clear();\n\t\t\tthis.commandTouchListener.clear();\n\t\t\tthis.commandKeyboardListener.clear();\n\n\t\t\tconst command = entry.command;\n\t\t\tif (command && (command !== ShowTooltipCommand || this.hover) /* \"Show Hover\" is only valid when we have a hover */) {\n\t\t\t\tthis.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));\n\t\t\t\tthis.commandTouchListener.value = addDisposableListener(this.labelContainer, TouchEventType.Tap, () => this.executeCommand(command));\n\t\t\t\tthis.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\t\tif (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tthis.executeCommand(command);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tthis.labelContainer.classList.remove('disabled');\n\t\t\t} else {\n\t\t\t\tthis.labelContainer.classList.add('disabled');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Beak\n\t\tif (!this.entry || entry.showBeak !== this.entry.showBeak) {\n\t\t\tif (entry.showBeak) {\n\t\t\t\tthis.container.classList.add('has-beak');\n\t\t\t} else {\n\t\t\t\tthis.container.classList.remove('has-beak');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Foreground\n\t\tif (!this.entry || entry.color !== this.entry.color) {\n\t\t\tthis.applyColor(this.labelContainer, entry.color);\n\t\t}\n\n\t\t// Update: Background\n\t\tif (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) {\n\t\t\tthis.container.classList.toggle('has-background-color', !!entry.backgroundColor);\n\t\t\tthis.applyColor(this.container, entry.backgroundColor, true);\n\t\t}\n\n\t\t// Remember for next round\n\t\tthis.entry = entry;\n\t}\n\n\tprivate isEqualTooltip({ tooltip }: IStatusbarEntry, { tooltip: otherTooltip }: IStatusbarEntry) {\n\t\tif (tooltip === undefined) {\n\t\t\treturn otherTooltip === undefined;\n\t\t}\n\n\t\tif (isMarkdownString(tooltip)) {\n\t\t\treturn isMarkdownString(otherTooltip) && markdownStringEqual(tooltip, otherTooltip);\n\t\t}\n\n\t\treturn tooltip === otherTooltip;\n\t}\n\n\tprivate async executeCommand(command: string | Command): Promise<void> {\n\n\t\t// Custom command from us: Show tooltip\n\t\tif (command === ShowTooltipCommand) {\n\t\t\tthis.hover?.show(true /* focus */);\n\t\t}\n\n\t\t// Any other command is going through command service\n\t\telse {\n\t\t\tconst id = typeof command === 'string' ? command : command.id;\n\t\t\tconst args = typeof command === 'string' ? [] : command.arguments ?? [];\n\n\t\t\tthis.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });\n\t\t\ttry {\n\t\t\t\tawait this.commandService.executeCommand(id, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.notificationService.error(toErrorMessage(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {\n\t\tlet colorResult: string | undefined = undefined;\n\n\t\tif (isBackground) {\n\t\t\tthis.backgroundListener.clear();\n\t\t} else {\n\t\t\tthis.foregroundListener.clear();\n\t\t}\n\n\t\tif (color) {\n\t\t\tif (isThemeColor(color)) {\n\t\t\t\tcolorResult = this.themeService.getColorTheme().getColor(color.id)?.toString();\n\n\t\t\t\tconst listener = this.themeService.onDidColorThemeChange(theme => {\n\t\t\t\t\tconst colorValue = theme.getColor(color.id)?.toString();\n\n\t\t\t\t\tif (isBackground) {\n\t\t\t\t\t\tcontainer.style.backgroundColor = colorValue ?? '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontainer.style.color = colorValue ?? '';\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (isBackground) {\n\t\t\t\t\tthis.backgroundListener.value = listener;\n\t\t\t\t} else {\n\t\t\t\t\tthis.foregroundListener.value = listener;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolorResult = color;\n\t\t\t}\n\t\t}\n\n\t\tif (isBackground) {\n\t\t\tcontainer.style.backgroundColor = colorResult ?? '';\n\t\t} else {\n\t\t\tcontainer.style.color = colorResult ?? '';\n\t\t}\n\t}\n}\n\nclass StatusBarCodiconLabel extends SimpleIconLabel {\n\n\tprivate progressCodicon = renderIcon(syncing);\n\n\tprivate currentText = '';\n\tprivate currentShowProgress = false;\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement\n\t) {\n\t\tsuper(container);\n\t}\n\n\tset showProgress(showProgress: boolean | 'syncing' | 'loading') {\n\t\tif (this.currentShowProgress !== showProgress) {\n\t\t\tthis.currentShowProgress = !!showProgress;\n\t\t\tthis.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);\n\t\t\tthis.text = this.currentText;\n\t\t}\n\t}\n\n\toverride set text(text: string) {\n\n\t\t// Progress: insert progress codicon as first element as needed\n\t\t// but keep it stable so that the animation does not reset\n\t\tif (this.currentShowProgress) {\n\n\t\t\t// Append as needed\n\t\t\tif (this.container.firstChild !== this.progressCodicon) {\n\t\t\t\tthis.container.appendChild(this.progressCodicon);\n\t\t\t}\n\n\t\t\t// Remove others\n\t\t\tfor (const node of Array.from(this.container.childNodes)) {\n\t\t\t\tif (node !== this.progressCodicon) {\n\t\t\t\t\tnode.remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have text to show, add a space to separate from progress\n\t\t\tlet textContent = text ?? '';\n\t\t\tif (textContent) {\n\t\t\t\ttextContent = ` ${textContent}`;\n\t\t\t}\n\n\t\t\t// Append new elements\n\t\t\tappend(this.container, ...renderLabelWithIcons(textContent));\n\t\t}\n\n\t\t// No Progress: no special handling\n\t\telse {\n\t\t\tsuper.text = text;\n\t\t}\n\t}\n}\n",
"initialResult": "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IStatusbarEntry, ShowTooltipCommand } from 'vs/workbench/services/statusbar/browser/statusbar';\nimport { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';\nimport { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';\nimport { isThemeColor } from 'vs/editor/common/editorCommon';\nimport { addDisposableListener, EventType, hide, show, append, EventHelper } from 'vs/base/browser/dom';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { Command } from 'vs/editor/common/languages';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { spinningLoading, syncing } from 'vs/platform/theme/common/iconRegistry';\nimport { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover';\nimport { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\n\nexport class StatusbarEntryItem extends Disposable {\n\n\tprivate readonly label: StatusBarCodiconLabel;\n\n\tprivate entry: IStatusbarEntry | undefined = undefined;\n\n\tprivate readonly foregroundListener = this._register(new MutableDisposable());\n\tprivate readonly backgroundListener = this._register(new MutableDisposable());\n\n\tprivate readonly commandMouseListener = this._register(new MutableDisposable());\n\tprivate readonly commandTouchListener = this._register(new MutableDisposable());\n\tprivate readonly commandKeyboardListener = this._register(new MutableDisposable());\n\n\tprivate hover: ICustomHover | undefined = undefined;\n\n\treadonly labelContainer: HTMLElement;\n\treadonly beakContainer: HTMLElement;\n\n\tget name(): string {\n\t\treturn assertIsDefined(this.entry).name;\n\t}\n\n\tget hasCommand(): boolean {\n\t\treturn typeof this.entry?.command !== 'undefined';\n\t}\n\n\tconstructor(\n\t\tprivate container: HTMLElement,\n\t\tentry: IStatusbarEntry,\n\t\tprivate readonly hoverDelegate: IHoverDelegate,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@INotificationService private readonly notificationService: INotificationService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IThemeService private readonly themeService: IThemeService\n\t) {\n\t\tsuper();\n\n\t\t// Label Container\n\t\tthis.labelContainer = document.createElement('a');\n\t\tthis.labelContainer.tabIndex = -1; // allows screen readers to read title, but still prevents tab focus.\n\t\tthis.labelContainer.setAttribute('role', 'button');\n\t\tthis._register(Gesture.addTarget(this.labelContainer)); // enable touch\n\n\t\t// Label (with support for progress)\n\t\tthis.label = new StatusBarCodiconLabel(this.labelContainer);\n\t\tthis.container.appendChild(this.labelContainer);\n\n\t\t// Beak Container\n\t\tthis.beakContainer = document.createElement('div');\n<<<<<<< c:\\dev\\microsoft\\diffing-dataset\\merges\\demo1\\input1.ts\n\t\tthis.beakContainer.className = 'status-bar-item-beak-container';\n=======\n\t\tthis.beakContainer.className = 'status-bar-beak-container';\n\n\t\t// Add to parent\n>>>>>>> c:\\dev\\microsoft\\diffing-dataset\\merges\\demo1\\input2.ts\n\t\tthis.container.appendChild(this.beakContainer);\n\n\t\tthis.update(entry);\n\t}\n\n\tupdate(entry: IStatusbarEntry): void {\n\n\t\t// Update: Progress\n\t\tthis.label.showProgress = entry.showProgress ?? false;\n\n\t\t// Update: Text\n\t\tif (!this.entry || entry.text !== this.entry.text) {\n\t\t\tthis.label.text = entry.text;\n\n\t\t\tif (entry.text) {\n\t\t\t\tshow(this.labelContainer);\n\t\t\t} else {\n\t\t\t\thide(this.labelContainer);\n\t\t\t}\n\t\t}\n\n\t\t// Update: ARIA label\n\t\t//\n\t\t// Set the aria label on both elements so screen readers would read\n\t\t// the correct thing without duplication #96210\n\n\t\tif (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {\n\t\t\tthis.container.setAttribute('aria-label', entry.ariaLabel);\n\t\t\tthis.labelContainer.setAttribute('aria-label', entry.ariaLabel);\n\t\t}\n\n\t\tif (!this.entry || entry.role !== this.entry.role) {\n\t\t\tthis.labelContainer.setAttribute('role', entry.role || 'button');\n\t\t}\n\n\t\t// Update: Hover\n\t\tif (!this.entry || !this.isEqualTooltip(this.entry, entry)) {\n\t\t\tconst hoverContents = isMarkdownString(entry.tooltip) ? { markdown: entry.tooltip, markdownNotSupportedFallback: undefined } : entry.tooltip;\n\t\t\tif (this.hover) {\n\t\t\t\tthis.hover.update(hoverContents);\n\t\t\t} else {\n\t\t\t\tthis.hover = this._register(setupCustomHover(this.hoverDelegate, this.container, hoverContents));\n\t\t\t}\n\t\t}\n\n\t\t// Update: Command\n\t\tif (!this.entry || entry.command !== this.entry.command) {\n\t\t\tthis.commandMouseListener.clear();\n\t\t\tthis.commandTouchListener.clear();\n\t\t\tthis.commandKeyboardListener.clear();\n\n\t\t\tconst command = entry.command;\n\t\t\tif (command && (command !== ShowTooltipCommand || this.hover) /* \"Show Hover\" is only valid when we have a hover */) {\n\t\t\t\tthis.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));\n\t\t\t\tthis.commandTouchListener.value = addDisposableListener(this.labelContainer, TouchEventType.Tap, () => this.executeCommand(command));\n\t\t\t\tthis.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {\n\t\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\t\tif (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\t\tEventHelper.stop(e);\n\n\t\t\t\t\t\tthis.executeCommand(command);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tthis.labelContainer.classList.remove('disabled');\n\t\t\t} else {\n\t\t\t\tthis.labelContainer.classList.add('disabled');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Beak\n\t\tif (!this.entry || entry.showBeak !== this.entry.showBeak) {\n\t\t\tif (entry.showBeak) {\n\t\t\t\tthis.container.classList.add('has-beak');\n\t\t\t} else {\n\t\t\t\tthis.container.classList.remove('has-beak');\n\t\t\t}\n\t\t}\n\n\t\t// Update: Foreground\n\t\tif (!this.entry || entry.color !== this.entry.color) {\n\t\t\tthis.applyColor(this.labelContainer, entry.color);\n\t\t}\n\n\t\t// Update: Background\n\t\tif (!this.entry || entry.backgroundColor !== this.entry.backgroundColor) {\n\t\t\tthis.container.classList.toggle('has-background-color', !!entry.backgroundColor);\n\t\t\tthis.applyColor(this.container, entry.backgroundColor, true);\n\t\t}\n\n\t\t// Remember for next round\n\t\tthis.entry = entry;\n\t}\n\n\tprivate isEqualTooltip({ tooltip }: IStatusbarEntry, { tooltip: otherTooltip }: IStatusbarEntry) {\n\t\tif (tooltip === undefined) {\n\t\t\treturn otherTooltip === undefined;\n\t\t}\n\n\t\tif (isMarkdownString(tooltip)) {\n\t\t\treturn isMarkdownString(otherTooltip) && markdownStringEqual(tooltip, otherTooltip);\n\t\t}\n\n\t\treturn tooltip === otherTooltip;\n\t}\n\n\tprivate async executeCommand(command: string | Command): Promise<void> {\n\n\t\t// Custom command from us: Show tooltip\n\t\tif (command === ShowTooltipCommand) {\n\t\t\tthis.hover?.show(true /* focus */);\n\t\t}\n\n\t\t// Any other command is going through command service\n\t\telse {\n\t\t\tconst id = typeof command === 'string' ? command : command.id;\n\t\t\tconst args = typeof command === 'string' ? [] : command.arguments ?? [];\n\n\t\t\tthis.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });\n\t\t\ttry {\n\t\t\t\tawait this.commandService.executeCommand(id, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.notificationService.error(toErrorMessage(error));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {\n\t\tlet colorResult: string | undefined = undefined;\n\n\t\tif (isBackground) {\n\t\t\tthis.backgroundListener.clear();\n\t\t} else {\n\t\t\tthis.foregroundListener.clear();\n\t\t}\n\n\t\tif (color) {\n\t\t\tif (isThemeColor(color)) {\n\t\t\t\tcolorResult = this.themeService.getColorTheme().getColor(color.id)?.toString();\n\n\t\t\t\tconst listener = this.themeService.onDidColorThemeChange(theme => {\n\t\t\t\t\tconst colorValue = theme.getColor(color.id)?.toString();\n\n\t\t\t\t\tif (isBackground) {\n\t\t\t\t\t\tcontainer.style.backgroundColor = colorValue ?? '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontainer.style.color = colorValue ?? '';\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (isBackground) {\n\t\t\t\t\tthis.backgroundListener.value = listener;\n\t\t\t\t} else {\n\t\t\t\t\tthis.foregroundListener.value = listener;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolorResult = color;\n\t\t\t}\n\t\t}\n\n\t\tif (isBackground) {\n\t\t\tcontainer.style.backgroundColor = colorResult ?? '';\n\t\t} else {\n\t\t\tcontainer.style.color = colorResult ?? '';\n\t\t}\n\t}\n}\n\nclass StatusBarCodiconLabel extends SimpleIconLabel {\n\n\tprivate progressCodicon = renderIcon(syncing);\n\n\tprivate currentText = '';\n\tprivate currentShowProgress = false;\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement\n\t) {\n\t\tsuper(container);\n\t}\n\n\tset showProgress(showProgress: boolean | 'syncing' | 'loading') {\n\t\tif (this.currentShowProgress !== showProgress) {\n\t\t\tthis.currentShowProgress = !!showProgress;\n\t\t\tthis.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);\n\t\t\tthis.text = this.currentText;\n\t\t}\n\t}\n\n\toverride set text(text: string) {\n\n\t\t// Progress: insert progress codicon as first element as needed\n\t\t// but keep it stable so that the animation does not reset\n\t\tif (this.currentShowProgress) {\n\n\t\t\t// Append as needed\n\t\t\tif (this.container.firstChild !== this.progressCodicon) {\n\t\t\t\tthis.container.appendChild(this.progressCodicon);\n\t\t\t}\n\n\t\t\t// Remove others\n\t\t\tfor (const node of Array.from(this.container.childNodes)) {\n\t\t\t\tif (node !== this.progressCodicon) {\n\t\t\t\t\tnode.remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have text to show, add a space to separate from progress\n\t\t\tlet textContent = text ?? '';\n\t\t\tif (textContent) {\n\t\t\t\ttextContent = ` ${textContent}`;\n\t\t\t}\n\n\t\t\t// Append new elements\n\t\t\tappend(this.container, ...renderLabelWithIcons(textContent));\n\t\t}\n\n\t\t// No Progress: no special handling\n\t\telse {\n\t\t\tsuper.text = text;\n\t\t}\n\t}\n}\n"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment