Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/vs/platform/hover/browser/hoverWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class HoverWidget extends Widget implements IHoverWidget {
private readonly _hoverContainer: HTMLElement;
private readonly _target: IHoverTarget;
private readonly _linkHandler: ((url: string) => void) | undefined;
private readonly _statusBarElement: HTMLElement[] = [];

private _isDisposed: boolean = false;
private _hoverPosition: HoverPosition;
Expand Down Expand Up @@ -222,6 +223,7 @@ export class HoverWidget extends Widget implements IHoverWidget {
});
statusBarElement.appendChild(actionsElement);
this._hover.containerDomNode.appendChild(statusBarElement);
this._statusBarElement.push(statusBarElement);
}

this._hoverContainer = $('div.workbench-hover-container');
Expand Down Expand Up @@ -254,6 +256,7 @@ export class HoverWidget extends Widget implements IHoverWidget {
infoElement.textContent = localize('hoverhint', 'Hold {0} key to mouse over', isMacintosh ? 'Option' : 'Alt');
statusBarElement.appendChild(infoElement);
this._hover.containerDomNode.appendChild(statusBarElement);
this._statusBarElement.push(statusBarElement);
}

const mouseTrackerTargets = [...this._target.targetElements];
Expand Down Expand Up @@ -342,6 +345,7 @@ export class HoverWidget extends Widget implements IHoverWidget {
public layout() {
this._hover.containerDomNode.classList.remove('right-aligned');
this._hover.contentsDomNode.style.maxHeight = '';
this._hover.scrollbar.getDomNode().style.maxHeight = '';

const getZoomAccountedBoundingClientRect = (e: HTMLElement) => {
const zoom = dom.getDomNodeZoomLevel(e);
Expand Down Expand Up @@ -585,6 +589,10 @@ export class HoverWidget extends Widget implements IHoverWidget {
}

this._hover.containerDomNode.style.maxHeight = `${maxHeight}px`;
const statusBarHeight = this._statusBarElement.reduce((total, el) => total + el.offsetHeight, 0);
const scrollableMaxHeight = Math.max(0, maxHeight - statusBarHeight);
this._hover.scrollbar.getDomNode().style.maxHeight = `${scrollableMaxHeight}px`;
this._hover.contentsDomNode.style.maxHeight = `${scrollableMaxHeight}px`;
if (this._hover.contentsDomNode.clientHeight < this._hover.contentsDomNode.scrollHeight) {
// Add padding for a vertical scrollbar
const extraRightPadding = `${this._hover.scrollbar.options.verticalScrollbarSize}px`;
Expand Down
20 changes: 20 additions & 0 deletions src/vs/platform/hover/test/browser/hoverService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ suite('HoverService', () => {
instantiationService.stub(IKeybindingService, {
mightProducePrintableCharacter() { return false; },
softDispatch() { return NoMatchingKb; },
lookupKeybinding() { return undefined; },
resolveKeyboardEvent() {
return {
getLabel() { return ''; },
Expand Down Expand Up @@ -242,6 +243,25 @@ suite('HoverService', () => {
hover.dispose();
assertNotInDOM(hover, 'Hover should be removed from DOM after dispose');
});

test('should constrain scrollable content height during layout', () => {
const target = createTarget();

const hover = hoverService.showInstantHover({
content: 'Test content',
target,
actions: [{ label: 'Test Action', commandId: 'test.action', run: () => { } }]
});

assert.ok(hover, 'Hover should be created');
assertInDOM(hover, 'Hover should be in DOM');

const contentsNode = asHoverWidget(hover).domNode.querySelector<HTMLElement>('.monaco-hover-content');
assert.ok(contentsNode, 'Contents node should exist');
assert.notStrictEqual(contentsNode.style.maxHeight, '', 'Contents node should have maxHeight set after layout so DomScrollableElement can detect overflow');

hover.dispose();
});
});

suite('hideHover', () => {
Expand Down