Code change:
<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IResizeEvent, ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IPosition } from 'vs/editor/common/core/position'; import { PositionAffinity } from 'vs/editor/common/model'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import * as dom from 'vs/base/browser/dom'; import { clamp } from 'vs/base/common/numbers'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Emitter, Event } from 'vs/base/common/event'; export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; constructor( private readonly _editor: ICodeEditor, private readonly _persistingOptions: IPersistingOptions, ) { console.log('Inside of ResizableWidget constructor'); this.element = new ResizableHTMLElement(); this.element.domNode.classList.add('editor-widget', 'resizable-widget'); if (this._persistingOptions instanceof SingleSizePersistingOptions) { this._persistingMechanism = new SingleSizePersistingMechanism(this, this.element, this._editor, this._persistingOptions); } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { this._persistingMechanism = new MultipleSizePersistingMechanism(this, this.element, this._editor); } else { throw new Error('Please specify a valid persisting mechanism'); } } dispose(): void { this._disposables.dispose(); this.element.dispose(); } resize(dimension: dom.Dimension): void { } hide(): void { this.element.clearSashHoverState(); } findMaximumRenderingHeight(): number | undefined { return Infinity; } findMaximumRenderingWidth(): number | undefined { return Infinity; } findPersistedSize(): dom.Dimension | undefined { return this._persistingMechanism.findSize(); } } export abstract class ResizableContentWidget implements IContentWidget { abstract ID: string; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { this.editor.addContentWidget(this); console.log('Inisde of ResizableContentWidget constructor'); } findPersistedSize(): dom.Dimension | undefined { return this.resizableWidget.findPersistedSize(); } getId(): string { console.log('this.ID : ', this.ID); return this.ID; } getDomNode(): HTMLElement { console.log('Inside of getDomNode of ResizableContentWidget'); console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); this.resizableWidget.element.domNode.style.zIndex = '49'; this.resizableWidget.element.domNode.style.position = 'fixed'; // this.resizableWidget.element.domNode.style.display = 'block'; return this.resizableWidget.element.domNode; } getPosition(): IContentWidgetPosition | null { console.log('Inside of getPosition of ResizableContentWidget'); const contentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, preference: (this._preference), positionAffinity: this._positionAffinity }; console.log('contentWidgetPosition: ', contentWidgetPosition); return contentWidgetPosition; } hide(): void { this.editor.layoutContentWidget(this); } set position(position: IPosition | null) { this._position = position; } set secondaryPosition(position: IPosition | null) { this._secondaryPosition = position; } set preference(preference: ContentWidgetPositionPreference[]) { this._preference = preference; } set positionAffinity(affinity: PositionAffinity | undefined) { this._positionAffinity = affinity; } } interface IPersistingOptions { } export class SingleSizePersistingOptions implements IPersistingOptions { constructor( public readonly key: string, public readonly defaultSize: dom.Dimension, @IStorageService public readonly storageService: IStorageService ) { } } export class MultipleSizePersistingOptions implements IPersistingOptions { constructor() { } } interface IPersistingMechanism extends IDisposable { findSize(): dom.Dimension | undefined; } // TODO: maybe need to make more generic, this is specific to the suggest widget class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSize: PersistedWidgetSize | null = null; private readonly _disposables = new DisposableStore(); constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, private readonly editor: ICodeEditor, private readonly persistingOptions: SingleSizePersistingOptions ) { this._persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService, this.editor); class ResizeState { constructor( readonly persistedSize: dom.Dimension | undefined, readonly currentSize: dom.Dimension, public persistHeight = false, public persistWidth = false, ) { } } let state: ResizeState | undefined; this._disposables.add(this.element.onDidWillResize(() => { // TODO: add back, this._contentWidget.lockPreference(); state = new ResizeState(this._persistedWidgetSize!.restore(), this.element.size); })); this._disposables.add(this.element.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; state.persistWidth = state.persistWidth || !!e.east || !!e.west; } if (!e.done) { return; } if (state) { const fontInfo = this.editor.getOption(EditorOption.fontInfo); const itemHeight = clamp(this.editor.getOption(EditorOption.suggestLineHeight) || fontInfo.lineHeight, 8, 1000); const threshold = Math.round(itemHeight / 2); let { width, height } = this.element.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; } if (!state.persistWidth || Math.abs(state.currentSize.width - width) <= threshold) { width = state.persistedSize?.width ?? this.persistingOptions.defaultSize.width; } this._persistedWidgetSize!.store(new dom.Dimension(width, height)); } // TODO: add back, reset working state // this._contentWidget.unlockPreference(); state = undefined; })); } findSize(): dom.Dimension | undefined { return undefined; } dispose(): void { this._disposables.dispose(); } } class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSizes: ResourceMap<Map<string, dom.Dimension>> = new ResourceMap<Map<string, dom.Dimension>>(); private readonly _disposables = new DisposableStore(); private _tooltipPosition: IPosition | null = null; // TODO: not sure if I need the following // private _initialHeight: number = 0; // private _initialTop: number = 0; private _resizing: boolean = false; private _size: dom.Dimension | undefined = undefined; private _maxRenderingHeight: number | undefined = Infinity; private _maxRenderingWidth: number | undefined = Infinity; private readonly _onDidResize = new Emitter<IResizeEvent>(); readonly onDidResize: Event<IResizeEvent> = this._onDidResize.event; // private _renderingAbove: ContentWidgetPositionPreference | undefined = undefined; constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, public readonly editor: ICodeEditor ) { this.element.minSize = new dom.Dimension(10, 24); this._disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; if (!uri || !this._persistedWidgetSizes.has(uri)) { return; } const persistedSizesForUri = this._persistedWidgetSizes.get(uri)!; const updatedPersistedSizesForUri = new Map<string, dom.Dimension>(); for (const change of e.changes) { const changeOffset = change.rangeOffset; const rangeLength = change.rangeLength; const endOffset = changeOffset + rangeLength; const textLength = change.text.length; for (const key of persistedSizesForUri.keys()) { const parsedKey = JSON.parse(key); const tokenOffset = parsedKey[0]; const tokenLength = parsedKey[1]; if (endOffset < tokenOffset) { const oldSize = persistedSizesForUri.get(key)!; const newKey: [number, number] = [tokenOffset - rangeLength + textLength, tokenLength]; updatedPersistedSizesForUri.set(JSON.stringify(newKey), oldSize); } else if (changeOffset >= tokenOffset + tokenLength) { updatedPersistedSizesForUri.set(key, persistedSizesForUri.get(key)!); } } } this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); this._disposables.add(this.element.onDidWillResize(() => { this._resizing = true; // this._initialHeight = this.element.domNode.clientHeight; // this._initialTop = this.element.domNode.offsetTop; })); this._disposables.add(this.element.onDidResize(e => { let height = e.dimension.height; let width = e.dimension.width; const maxWidth = this.element.maxSize.width; const maxHeight = this.element.maxSize.height; width = Math.min(maxWidth, width); height = Math.min(maxHeight, height); if (!this._maxRenderingHeight) { return; } this._size = new dom.Dimension(width, height); this.element.layout(height, width); // Calling the resize function of the this.resizableWidget.resize(new dom.Dimension(width, height)); // Update the top parameters only when we decided to render above // TODO: presumably do not need to resize the element // if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { // 	this.element.domNode.style.top = this._initialTop - (height - this._initialHeight) + 'px'; // } // const horizontalSashWidth = width - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.northSash.el.style.width = horizontalSashWidth; // this.element.southSash.el.style.width = horizontalSashWidth; // const verticalSashWidth = height - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.eastSash.el.style.height = verticalSashWidth; // this.element.westSash.el.style.height = verticalSashWidth; // this.element.eastSash.el.style.top = TOTAL_BORDER_WIDTH + 'px'; // Fire the current dimension // TODO: probably don't need to listen on the firing event? // this._onDidResize.fire({ dimension: this._size, done: false }); this._maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); // this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(this._renderingAbove); if (!this._maxRenderingHeight || !this._maxRenderingWidth) { return; } this.element.maxSize = new dom.Dimension(this._maxRenderingWidth, this._maxRenderingHeight); // Persist the height only when the resizing has stopped if (e.done) { if (!this.editor.hasModel()) { return; } const uri = this.editor.getModel().uri; if (!uri || !this._tooltipPosition) { return; } const persistedSize = new dom.Dimension(width, height); const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; // Suppose that the uri does not exist in the persisted widget hover sizes, then create a map if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map<string, dom.Dimension>([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); this._persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); } else { const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } this._resizing = false; } // this.editor.layoutOverlayWidget(this); // this.editor.render(); })); } set tooltipPosition(position: IPosition) { this._tooltipPosition = position; } findSize(): dom.Dimension | undefined { console.log('Inside of findSize of the MultiplePersistingMechanisms'); if (!this._tooltipPosition || !this.editor.hasModel()) { return; } const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; const uri = this.editor.getModel().uri; const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; } return persistedSizesForUri.get(JSON.stringify([offset, length])); } dispose(): void { this._disposables.dispose(); } } class PersistedWidgetSize { constructor( private readonly _key: string, private readonly _service: IStorageService, editor: ICodeEditor ) { } restore(): dom.Dimension | undefined { const raw = this._service.get(this._key, StorageScope.PROFILE) ?? ''; try { const obj = JSON.parse(raw); if (dom.Dimension.is(obj)) { return dom.Dimension.lift(obj); } } catch { // ignore } return undefined; } store(size: dom.Dimension) { this._service.store(this._key, JSON.stringify(size), StorageScope.PROFILE, StorageTarget.MACHINE); } reset(): void { this._service.remove(this._key, StorageScope.PROFILE); } } </ins>

Related discussion:
text: When you hover over a type in a TypeScript file, the tooltip that appears has a very low max width, making it difficult to read long type signatures.
I would include a screenshot but it's not easy to take a screenshot keeping the tooltip on screen!
! Errors are quite unreadable if the width does not adapt to the font size.
! it would be nice if the tip used the available space instead of wrapping at an arbitrary point in c# too
!
! Same problem using rust's language server.
General styling control would be very helpful. Also line-height. Another approach would be to have a bottom panel that displays the full error and the tooltip displays a shortened version.
!
! When using the auto import feature it is often impossible to differentiate whats what as the import path is cut off due to the limited width of the suggestions window.
Is this something we can adjust with custom css? It makes snippet infoormation very difficult to read as well. !
Same in Python. We have to jump through hoops trying to flow doc nicely. And when it appears OK on Windows, it breaks on Mac... ! And it is inconsistent. Ex, hover is OK ! But completion list decides to wrap. What gives? ! Looks like hover respects markdown while completion item doc is plain string and gets wrapped randomly.
!
Someone say long type signatures? !
Here is a workaround by hacking the file "C:Program FilesMicrosoft VS Coderesourcesappoutvsworkbench" Simply append the code above after the original content of file, and restart VSCode. (Title bar may alert a warning message "Not Supported" and hacked changes would be overridden by updating VSCode) !
It would be nice to have some control on the width. The above does work but vscode presents the message your installation may be corrupt on restarting.
Instead of hacking the CSS directly as mentioned above, I recommend using the to just override the current CSS. That way when VSCode updates, you can just reload the custom css file that you have specified (personally, I have a project where I hold configurations for my shell, Spacemacs, etc. and this custom CSS file goes there). Until it's officially supported, hacking the CSS is likely the best route.