From e1becd2eb899b7da53bc7c8d0a6bdf12587a69ba Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 12 Jul 2023 12:49:48 +0200 Subject: [PATCH 1/4] cleaning the code, it works now --- .../lib/stylelint/vscode-known-variables.json | 2 ++ src/vs/base/browser/ui/hover/hover.css | 3 +- .../contrib/hover/browser/contentHover.ts | 30 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 67ec595ed30..7ff08b74263 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -306,6 +306,8 @@ "--vscode-extensionIcon-verifiedForeground", "--vscode-focusBorder", "--vscode-foreground", + "--vscode-hover-whiteSpace", + "--vscode-hoverSource-whiteSpace", "--vscode-icon-foreground", "--vscode-inlineChat-background", "--vscode-inlineChat-border", diff --git a/src/vs/base/browser/ui/hover/hover.css b/src/vs/base/browser/ui/hover/hover.css index 0ce58199354..68907c6a062 100644 --- a/src/vs/base/browser/ui/hover/hover.css +++ b/src/vs/base/browser/ui/hover/hover.css @@ -12,6 +12,7 @@ box-sizing: border-box; animation: fadein 100ms linear; line-height: 1.5em; + white-space: var(--vscode-hover-whiteSpace); } .monaco-hover.hidden { @@ -105,7 +106,7 @@ } .monaco-hover .monaco-tokenized-source { - white-space: pre-wrap; + white-space: var(--vscode-hoverSource-whiteSpace); } .monaco-hover .hover-row.status-bar { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index e284a838116..885b1f41c7d 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -459,6 +459,7 @@ export class ContentHoverWidget extends ResizableContentWidget { private _visibleData: ContentHoverVisibleData | undefined; private _positionPreference: ContentWidgetPositionPreference | undefined; + private _initialWidth: number | undefined; private readonly _hover: HoverWidget = this._register(new HoverWidget()); private readonly _hoverVisibleKey: IContextKey; @@ -612,13 +613,29 @@ export class ContentHoverWidget extends ResizableContentWidget { return Math.min(availableSpace, maximumHeight); } + private _isHoverTextOverflowing(): boolean { + let overflowing = false; + Array.from(this._hover.contentsDomNode.children).forEach((hoverPart) => { + overflowing = overflowing || hoverPart.scrollWidth > hoverPart.clientWidth; + }); + return overflowing; + } + private _findMaximumRenderingWidth(): number | undefined { if (!this._editor || !this._editor.hasModel()) { return; } - const bodyBoxWidth = dom.getClientArea(document.body).width; - const horizontalPadding = 14; - return bodyBoxWidth - horizontalPadding; + this._setWhiteSpaceProperties('nowrap', 'nowrap'); + const overflowing = this._isHoverTextOverflowing(); + this._setWhiteSpaceProperties('normal', 'pre-wrap'); + + if (overflowing || this._initialWidth && this._hover.containerDomNode.clientWidth < this._initialWidth) { + const bodyBoxWidth = dom.getClientArea(document.body).width; + const horizontalPadding = 14; + return bodyBoxWidth - horizontalPadding; + } else { + return this._hover.containerDomNode.clientWidth + 2; + } } public isMouseGettingCloser(posx: number, posy: number): boolean { @@ -707,10 +724,16 @@ export class ContentHoverWidget extends ResizableContentWidget { }; } + private _setWhiteSpaceProperties(hoverWhiteSpace: 'normal' | 'nowrap', hoverSourceWhiteSpace: 'pre-wrap' | 'nowrap') { + this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', hoverWhiteSpace); + this._hover.containerDomNode.style.setProperty('--vscode-hoverSource-whiteSpace', hoverSourceWhiteSpace); + } + public showAt(node: DocumentFragment, hoverData: ContentHoverVisibleData): void { if (!this._editor || !this._editor.hasModel()) { return; } + this._setWhiteSpaceProperties('normal', 'pre-wrap'); this._render(node, hoverData); const widgetHeight = dom.getTotalHeight(this._hover.containerDomNode); const widgetPosition = hoverData.showAtPosition; @@ -774,6 +797,7 @@ export class ContentHoverWidget extends ResizableContentWidget { this._adjustHoverHeightForScrollbar(height); } this._layoutContentWidget(); + this._initialWidth = this._hover.containerDomNode.clientWidth; } public focus(): void { From 101c247b5bb061d9274509745175b5cd5a2bb840 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 12 Jul 2023 15:12:37 +0200 Subject: [PATCH 2/4] commiting in order to retrigger the checks on github --- src/vs/editor/contrib/hover/browser/contentHover.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 885b1f41c7d..12c126e30bd 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -604,8 +604,8 @@ export class ContentHoverWidget extends ResizableContentWidget { } // Padding needed in order to stop the resizing down to a smaller height let maximumHeight = CONTAINER_HEIGHT_PADDING; - Array.from(this._hover.contentsDomNode.children).forEach((hoverPart) => { - maximumHeight += hoverPart.clientHeight; + Array.from(this._hover.contentsDomNode.children).forEach((hoverElement) => { + maximumHeight += hoverElement.clientHeight; }); if (this._hasHorizontalScrollbar()) { maximumHeight += SCROLLBAR_WIDTH; @@ -615,8 +615,8 @@ export class ContentHoverWidget extends ResizableContentWidget { private _isHoverTextOverflowing(): boolean { let overflowing = false; - Array.from(this._hover.contentsDomNode.children).forEach((hoverPart) => { - overflowing = overflowing || hoverPart.scrollWidth > hoverPart.clientWidth; + Array.from(this._hover.contentsDomNode.children).forEach((hoverElement) => { + overflowing = overflowing || hoverElement.scrollWidth > hoverElement.clientWidth; }); return overflowing; } From 684270ac2efa142c4401bb3d3937c97f02d5704b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 11 Aug 2023 17:39:24 +0200 Subject: [PATCH 3/4] Use consistent names for variables, fall back to defaults when wrapping is on --- .../lib/stylelint/vscode-known-variables.json | 8 ++++---- src/vs/base/browser/ui/hover/hover.css | 6 +++--- .../contrib/hover/browser/contentHover.ts | 20 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index ca1f5eab147..577b3f13669 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -310,8 +310,6 @@ "--vscode-extensionIcon-verifiedForeground", "--vscode-focusBorder", "--vscode-foreground", - "--vscode-hover-whiteSpace", - "--vscode-hoverSource-whiteSpace", "--vscode-icon-foreground", "--vscode-inlineChat-background", "--vscode-inlineChat-border", @@ -705,7 +703,6 @@ "--background-light", "--dropdown-padding-bottom", "--dropdown-padding-top", - "--hover-maxWidth", "--insert-border-color", "--last-tab-margin-right", "--monaco-monospace-font", @@ -735,6 +732,9 @@ "--vscode-editorCodeLens-fontSize", "--vscode-editorCodeLens-lineHeight", "--vscode-explorer-align-offset-margin-left", + "--vscode-hover-maxWidth", + "--vscode-hover-sourceWhiteSpace", + "--vscode-hover-whiteSpace", "--vscode-inline-chat-cropped", "--vscode-inline-chat-expanded", "--vscode-interactive-session-foreground", @@ -768,4 +768,4 @@ "--z-index-notebook-sticky-scroll", "--zoom-factor" ] -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/hover/hover.css b/src/vs/base/browser/ui/hover/hover.css index 5e12d070057..ee294b766fb 100644 --- a/src/vs/base/browser/ui/hover/hover.css +++ b/src/vs/base/browser/ui/hover/hover.css @@ -12,7 +12,7 @@ box-sizing: border-box; animation: fadein 100ms linear; line-height: 1.5em; - white-space: var(--vscode-hover-whiteSpace); + white-space: var(--vscode-hover-whiteSpace, normal); } .monaco-hover.hidden { @@ -28,7 +28,7 @@ } .monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) { - max-width: var(--hover-maxWidth, 500px); + max-width: var(--vscode-hover-maxWidth, 500px); word-wrap: break-word; } @@ -106,7 +106,7 @@ } .monaco-hover .monaco-tokenized-source { - white-space: var(--vscode-hoverSource-whiteSpace); + white-space: var(--vscode-hover-sourceWhiteSpace, pre-wrap); } .monaco-hover .hover-row.status-bar { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 841c5cd2a34..4e6002b5880 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -576,7 +576,7 @@ export class ContentHoverWidget extends ResizableContentWidget { private _setHoverWidgetMaxDimensions(width: number | string, height: number | string): void { ContentHoverWidget._applyMaxDimensions(this._hover.contentsDomNode, width, height); ContentHoverWidget._applyMaxDimensions(this._hover.containerDomNode, width, height); - this._hover.containerDomNode.style.setProperty('--hover-maxWidth', typeof width === 'number' ? `${width}px` : width); + this._hover.containerDomNode.style.setProperty('--vscode-hover-maxWidth', typeof width === 'number' ? `${width}px` : width); this._layoutContentWidget(); } @@ -659,11 +659,11 @@ export class ContentHoverWidget extends ResizableContentWidget { if (!this._editor || !this._editor.hasModel()) { return; } - this._setWhiteSpaceProperties('nowrap', 'nowrap'); + this._setHoverWrapping(false); const overflowing = this._isHoverTextOverflowing(); - this._setWhiteSpaceProperties('normal', 'pre-wrap'); + this._setHoverWrapping(true); - if (overflowing || this._initialWidth && this._hover.containerDomNode.clientWidth < this._initialWidth) { + if (overflowing || (this._initialWidth && this._hover.containerDomNode.clientWidth < this._initialWidth)) { const bodyBoxWidth = dom.getClientArea(document.body).width; const horizontalPadding = 14; return bodyBoxWidth - horizontalPadding; @@ -756,16 +756,20 @@ export class ContentHoverWidget extends ResizableContentWidget { }; } - private _setWhiteSpaceProperties(hoverWhiteSpace: 'normal' | 'nowrap', hoverSourceWhiteSpace: 'pre-wrap' | 'nowrap') { - this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', hoverWhiteSpace); - this._hover.containerDomNode.style.setProperty('--vscode-hoverSource-whiteSpace', hoverSourceWhiteSpace); + private _setHoverWrapping(shouldWrap: boolean): void { + if (shouldWrap) { + this._hover.containerDomNode.style.removeProperty('--vscode-hover-whiteSpace'); + this._hover.containerDomNode.style.removeProperty('--vscode-hover-sourceWhiteSpace'); + } else { + this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', 'nowrap'); + this._hover.containerDomNode.style.setProperty('--vscode-hover-sourceWhiteSpace', 'nowrap'); + } } public showAt(node: DocumentFragment, hoverData: ContentHoverVisibleData): void { if (!this._editor || !this._editor.hasModel()) { return; } - this._setWhiteSpaceProperties('normal', 'pre-wrap'); this._render(node, hoverData); const widgetHeight = dom.getTotalHeight(this._hover.containerDomNode); const widgetPosition = hoverData.showAtPosition; From 00b98a892a01c797f64d9fdf8c7a8d9daf7c26d5 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 11 Aug 2023 18:07:22 +0200 Subject: [PATCH 4/4] Reuse `_contentWidth` --- .../contrib/hover/browser/contentHover.ts | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 191d3f23aef..dba7c1531b5 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -474,8 +474,7 @@ export class ContentHoverWidget extends ResizableContentWidget { private _visibleData: ContentHoverVisibleData | undefined; private _positionPreference: ContentWidgetPositionPreference | undefined; private _minimumSize: dom.Dimension; - private _contentWidth: number; - private _initialWidth: number | undefined; + private _contentWidth: number | undefined; private readonly _hover: HoverWidget = this._register(new HoverWidget()); private readonly _hoverVisibleKey: IContextKey; @@ -509,7 +508,6 @@ export class ContentHoverWidget extends ResizableContentWidget { const minimumSize = new dom.Dimension(minimumWidth, minimumHeight); super(editor, minimumSize); this._minimumSize = minimumSize; - this._contentWidth = minimumWidth; // we initially assume the content width to be the minimum width this._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(contextKeyService); this._hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(contextKeyService); @@ -609,7 +607,7 @@ export class ContentHoverWidget extends ResizableContentWidget { } } - private _setResizableNodeMaxDimensions(): void { + private _updateResizableNodeMaxDimensions(): void { const maxRenderingWidth = this._findMaximumRenderingWidth() ?? Infinity; const maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity; this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); @@ -620,7 +618,7 @@ export class ContentHoverWidget extends ResizableContentWidget { ContentHoverWidget._lastDimensions = new dom.Dimension(size.width, size.height); this._setAdjustedHoverWidgetDimensions(size); this._resizableNode.layout(size.height, size.width); - this._setResizableNodeMaxDimensions(); + this._updateResizableNodeMaxDimensions(); this._hover.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); this._visibleData?.colorPicker?.layout(); @@ -641,8 +639,8 @@ export class ContentHoverWidget extends ResizableContentWidget { } // Padding needed in order to stop the resizing down to a smaller height let maximumHeight = CONTAINER_HEIGHT_PADDING; - Array.from(this._hover.contentsDomNode.children).forEach((hoverElement) => { - maximumHeight += hoverElement.clientHeight; + Array.from(this._hover.contentsDomNode.children).forEach((hoverPart) => { + maximumHeight += hoverPart.clientHeight; }); if (this._hasHorizontalScrollbar()) { maximumHeight += SCROLLBAR_WIDTH; @@ -651,10 +649,17 @@ export class ContentHoverWidget extends ResizableContentWidget { } private _isHoverTextOverflowing(): boolean { - let overflowing = false; - Array.from(this._hover.contentsDomNode.children).forEach((hoverElement) => { - overflowing = overflowing || hoverElement.scrollWidth > hoverElement.clientWidth; + // To find out if the text is overflowing, we will disable wrapping, check the widths, and then re-enable wrapping + this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', 'nowrap'); + this._hover.containerDomNode.style.setProperty('--vscode-hover-sourceWhiteSpace', 'nowrap'); + + const overflowing = Array.from(this._hover.contentsDomNode.children).some((hoverElement) => { + return hoverElement.scrollWidth > hoverElement.clientWidth; }); + + this._hover.containerDomNode.style.removeProperty('--vscode-hover-whiteSpace'); + this._hover.containerDomNode.style.removeProperty('--vscode-hover-sourceWhiteSpace'); + return overflowing; } @@ -662,11 +667,16 @@ export class ContentHoverWidget extends ResizableContentWidget { if (!this._editor || !this._editor.hasModel()) { return; } - this._setHoverWrapping(false); - const overflowing = this._isHoverTextOverflowing(); - this._setHoverWrapping(true); - if (overflowing || (this._initialWidth && this._hover.containerDomNode.clientWidth < this._initialWidth)) { + const overflowing = this._isHoverTextOverflowing(); + + const initialWidth = ( + typeof this._contentWidth === 'undefined' + ? 0 + : this._contentWidth - 2 // - 2 for the borders + ); + + if (overflowing || this._hover.containerDomNode.clientWidth < initialWidth) { const bodyBoxWidth = dom.getClientArea(document.body).width; const horizontalPadding = 14; return bodyBoxWidth - horizontalPadding; @@ -759,16 +769,6 @@ export class ContentHoverWidget extends ResizableContentWidget { }; } - private _setHoverWrapping(shouldWrap: boolean): void { - if (shouldWrap) { - this._hover.containerDomNode.style.removeProperty('--vscode-hover-whiteSpace'); - this._hover.containerDomNode.style.removeProperty('--vscode-hover-sourceWhiteSpace'); - } else { - this._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', 'nowrap'); - this._hover.containerDomNode.style.setProperty('--vscode-hover-sourceWhiteSpace', 'nowrap'); - } - } - public showAt(node: DocumentFragment, hoverData: ContentHoverVisibleData): void { if (!this._editor || !this._editor.hasModel()) { return; @@ -827,8 +827,13 @@ export class ContentHoverWidget extends ResizableContentWidget { } private _updateMinimumWidth(): void { + const width = ( + typeof this._contentWidth === 'undefined' + ? this._minimumSize.width + : Math.min(this._contentWidth, this._minimumSize.width) + ); // We want to avoid that the hover is artificially large, so we use the content width as minimum width - this._resizableNode.minSize = new dom.Dimension(Math.min(this._contentWidth, this._minimumSize.width), this._minimumSize.height); + this._resizableNode.minSize = new dom.Dimension(width, this._minimumSize.height); } public onContentsChanged(): void { @@ -845,6 +850,7 @@ export class ContentHoverWidget extends ResizableContentWidget { width = dom.getTotalWidth(containerDomNode); this._contentWidth = width; this._updateMinimumWidth(); + this._updateResizableNodeMaxDimensions(); this._resizableNode.layout(height, width); if (this._hasHorizontalScrollbar()) { @@ -856,7 +862,6 @@ export class ContentHoverWidget extends ResizableContentWidget { this._positionPreference = this._findPositionPreference(widgetHeight, this._visibleData.showAtPosition); } this._layoutContentWidget(); - this._initialWidth = this._hover.containerDomNode.clientWidth; } public focus(): void {