Skip to content

Merge Editor: Provide a 4-editor view which also shows the base editor #155277

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

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions