From f6fc0742aca0929a5174532e82f03d4de2e20060 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 15:57:45 +0200 Subject: [PATCH 01/72] creating a generic resizable content widget type which can be used to implement the resizable hover and the resizable suggest widget --- src/vs/base/browser/ui/hover/hover.css | 1 - .../hover/browser/resizableContentWidget.css | 10 + .../hover/browser/resizableContentWidget.ts | 407 ++++++++++++++++++ 3 files changed, 417 insertions(+), 1 deletion(-) create mode 100644 src/vs/editor/contrib/hover/browser/resizableContentWidget.css create mode 100644 src/vs/editor/contrib/hover/browser/resizableContentWidget.ts diff --git a/src/vs/base/browser/ui/hover/hover.css b/src/vs/base/browser/ui/hover/hover.css index f3058d6c10709..5f867a8913f07 100644 --- a/src/vs/base/browser/ui/hover/hover.css +++ b/src/vs/base/browser/ui/hover/hover.css @@ -28,7 +28,6 @@ } .monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) { - max-width: 500px; word-wrap: break-word; } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.css b/src/vs/editor/contrib/hover/browser/resizableContentWidget.css new file mode 100644 index 0000000000000..48840ea0931df --- /dev/null +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.css @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-editor .resizable-widget { + z-index: 40; + display: flex; + flex-direction: column; +} diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts new file mode 100644 index 0000000000000..b87405f28541d --- /dev/null +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -0,0 +1,407 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; + +// TODO: need several types of constructors depending on what kind of resizable element we will be creating +export abstract class ResizableWidget implements IDisposable { + + readonly element: ResizableHTMLElement; + readonly _domNode: HTMLElement; + private readonly _disposables = new DisposableStore(); + private readonly _persistingMechanism: IPersistingMechanism; + private _renderingAbove: ContentWidgetPositionPreference = ContentWidgetPositionPreference.ABOVE; + + constructor( + // The ContentWidget is within a disposable and the disposable can be instatiated + private readonly _resizableContentWidget: ResizableContentWidget, + private readonly _editor: ICodeEditor, + private readonly _contents: HTMLElement, + private readonly _persistingOptions: IPersistingOptions, + ) { + this.element = new ResizableHTMLElement(); + this.element.domNode.classList.add('editor-widget', 'resizable-widget'); + + // TODO: setting the resizable widget to this instance like for the suggest widget + this._resizableContentWidget.resizableWidget = this; + this._domNode = dom.append(this.element.domNode, this._contents); + + 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(width: number, height: number): void { } + + hide(): void { + this.element.clearSashHoverState(); + } + + findMaximumRenderingHeight(): number { + return Infinity; + } + + findMaximumRenderingWidth(): number { + return Infinity; + } +} + +export abstract class ResizableContentWidget implements IContentWidget { + + // Previously was a static variable now it is a private one + private _ID: string = ''; + private _resizableWidget: ResizableWidget | null = null; + private _position: IPosition | null = null; + private _secondaryPosition: IPosition | null = null; + private _preference: ContentWidgetPositionPreference[] = []; + private _positionAffinity: PositionAffinity | undefined = undefined; + + constructor( + private readonly editor: ICodeEditor, + ) { } + + set resizableWidget(resizableWidget: ResizableWidget) { + this._resizableWidget = resizableWidget; + } + + // TODO: mus tbe implemented by the child class + abstract set ID(id: string); + + getId(): string { + return this._ID; + } + + getDomNode(): HTMLElement { + if (this._resizableWidget) { + return this._resizableWidget.element.domNode; + } else { + return new HTMLElement(); + } + } + + getPosition(): IContentWidgetPosition | null { + return { + position: this._position, + secondaryPosition: this._secondaryPosition, + preference: (this._preference), + positionAffinity: this._positionAffinity + }; + } + + 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; +} + +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(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; + } + + // TODO: maybe need to make more generic, this is specific to the suggest widget + 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> = new ResourceMap>(); + 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 = Infinity; + private _maxRenderingWidth: number = Infinity; + + private readonly _onDidResize = new Emitter(); + readonly onDidResize: Event = 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(); + 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); + + // 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 + 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([]); + 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 { + 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); + } +} From ea010f6153e9e67f2cb0555ade0782c7170b43b6 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 16:54:22 +0200 Subject: [PATCH 02/72] adding code for the hover specific widgets and content widgets --- .../contrib/hover/browser/contentHover.ts | 4 ++ .../hover/browser/resizableContentWidget.ts | 36 +++++---------- .../hover/browser/resizableHoverWidget.ts | 44 +++++++++++++++++++ .../suggest/browser/suggestController.ts | 2 + .../contrib/suggest/browser/suggestWidget.ts | 2 + 5 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 26741f8e03324..49dae9623b1dc 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -30,7 +30,11 @@ const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; + // TODO: instead of making an instance of the content hover widget, make an instance of the resizable content hover widget private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); + + // TODO: private readonly _resizableOverlay = this._register(this._instantiationService.createInstance(ResizableContentHoverWidget, this._editor)); + private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index b87405f28541d..2a4e876966c88 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -19,24 +19,23 @@ import { Emitter, Event } from 'vs/base/common/event'; export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; - readonly _domNode: HTMLElement; + // readonly _domNode: HTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; + + // TODO: do I need this? private _renderingAbove: ContentWidgetPositionPreference = ContentWidgetPositionPreference.ABOVE; constructor( - // The ContentWidget is within a disposable and the disposable can be instatiated - private readonly _resizableContentWidget: ResizableContentWidget, private readonly _editor: ICodeEditor, - private readonly _contents: HTMLElement, private readonly _persistingOptions: IPersistingOptions, ) { this.element = new ResizableHTMLElement(); this.element.domNode.classList.add('editor-widget', 'resizable-widget'); // TODO: setting the resizable widget to this instance like for the suggest widget - this._resizableContentWidget.resizableWidget = this; - this._domNode = dom.append(this.element.domNode, this._contents); + // TODO: this._resizableContentWidget.resizableWidget = this; + // TODO: this._domNode = dom.append(this.element.domNode, this._contents); if (this._persistingOptions instanceof SingleSizePersistingOptions) { this._persistingMechanism = new SingleSizePersistingMechanism(this, this.element, this._editor, this._persistingOptions); @@ -70,34 +69,20 @@ export abstract class ResizableWidget implements IDisposable { export abstract class ResizableContentWidget implements IContentWidget { // Previously was a static variable now it is a private one - private _ID: string = ''; - private _resizableWidget: ResizableWidget | null = null; + abstract ID: string; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; - constructor( - private readonly editor: ICodeEditor, - ) { } - - set resizableWidget(resizableWidget: ResizableWidget) { - this._resizableWidget = resizableWidget; - } - - // TODO: mus tbe implemented by the child class - abstract set ID(id: string); + constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { } getId(): string { - return this._ID; + return this.ID; } getDomNode(): HTMLElement { - if (this._resizableWidget) { - return this._resizableWidget.element.domNode; - } else { - return new HTMLElement(); - } + return this.resizableWidget.element.domNode; } getPosition(): IContentWidgetPosition | null { @@ -109,6 +94,9 @@ export abstract class ResizableContentWidget implements IContentWidget { }; } + hide(): void { + this.editor.layoutContentWidget(this); + } set position(position: IPosition | null) { this._position = position; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts new file mode 100644 index 0000000000000..3e8a2c0e20c22 --- /dev/null +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; + + +class ResizableHovertWidget extends ResizableWidget { + + public ID = 'editor.contrib.resizableContentHoverWidget'; + private _hoverDisposables = new DisposableStore(); + + // TODO: Element from the abstract super class + // abstract properties have to be public? + resizableContentWidget: ResizableContentHoverWidget; + + constructor( + editor: ICodeEditor + ) { + super(editor, new MultipleSizePersistingOptions()); + + // create here the dom node and all other logic should go here that was in the super abstract class + this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); + + // element is a property of the resizable hover widget + this._hoverDisposables.add(this.element.onDidResize((e) => { + // When the resizable hover overlay changes, resize the widget + // this._widget.resize(e.dimension); + })); + } +} + +class ResizableContentHoverWidget extends ResizableContentWidget { + + public ID = 'editor.contrib.resizableContentHoverWidget'; + private _hoverDisposables = new DisposableStore(); + + constructor(resizableHoverWidget: ResizableHovertWidget, editor: ICodeEditor) { + super(resizableHoverWidget, editor); + } +} diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index abd5d8b23bb7c..ed994e029dcb3 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -144,6 +144,8 @@ export class SuggestController implements IEditorContribution { this.widget = this._toDispose.add(new IdleValue(() => { + // TODO: The point where the suggest widget instance is created + // TODO: suggest widget should be mapped to the content hover widget const widget = this._instantiationService.createInstance(SuggestWidget, this.editor); this._toDispose.add(widget); diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index d2e86783c8a0f..d30d9b3f51a2d 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -96,6 +96,7 @@ class PersistedWidgetSize { } } +// TODO: The suggest widget is a disposable and it can be instantiated export class SuggestWidget implements IDisposable { private static LOADING_MESSAGE: string = nls.localize('suggestWidget.loading', "Loading..."); @@ -921,6 +922,7 @@ export class SuggestWidget implements IDisposable { } } +// TODO: The suggest content widget is a content widget and it belongs to the suggest widget export class SuggestContentWidget implements IContentWidget { readonly allowEditorOverflow = true; From f5c37fbe337fbd302a5254d2a146450926ee7e5f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 17:53:00 +0200 Subject: [PATCH 03/72] Adding some code --- .../contrib/hover/browser/contentHover.ts | 2 +- .../hover/browser/resizableContentWidget.ts | 25 +- .../hover/browser/resizableHoverWidget.ts | 484 +++++++++++++++++- 3 files changed, 490 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 49dae9623b1dc..dd3367e423118 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -423,7 +423,7 @@ class FilteredHoverResult extends HoverResult { } } -class ContentHoverVisibleData { +export class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 2a4e876966c88..9f1599487fe38 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -24,7 +24,7 @@ export abstract class ResizableWidget implements IDisposable { private readonly _persistingMechanism: IPersistingMechanism; // TODO: do I need this? - private _renderingAbove: ContentWidgetPositionPreference = ContentWidgetPositionPreference.ABOVE; + // private _renderingAbove: ContentWidgetPositionPreference = ContentWidgetPositionPreference.ABOVE; constructor( private readonly _editor: ICodeEditor, @@ -51,17 +51,18 @@ export abstract class ResizableWidget implements IDisposable { this.element.dispose(); } - resize(width: number, height: number): void { } + resize(dimension: dom.Dimension): void { + } hide(): void { this.element.clearSashHoverState(); } - findMaximumRenderingHeight(): number { + findMaximumRenderingHeight(): number | undefined { return Infinity; } - findMaximumRenderingWidth(): number { + findMaximumRenderingWidth(): number | undefined { return Infinity; } } @@ -75,7 +76,9 @@ export abstract class ResizableContentWidget implements IContentWidget { private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; - constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { } + constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { + this.editor.addContentWidget(this); + } getId(): string { return this.ID; @@ -97,6 +100,7 @@ export abstract class ResizableContentWidget implements IContentWidget { hide(): void { this.editor.layoutContentWidget(this); } + set position(position: IPosition | null) { this._position = position; } @@ -162,7 +166,7 @@ class SingleSizePersistingMechanism implements IPersistingMechanism { })); this._disposables.add(this.element.onDidResize(e => { - this.resizableWidget.resize(e.dimension.width, e.dimension.height); + this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; @@ -215,8 +219,8 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { private _resizing: boolean = false; private _size: dom.Dimension | undefined = undefined; - private _maxRenderingHeight: number = Infinity; - private _maxRenderingWidth: number = Infinity; + private _maxRenderingHeight: number | undefined = Infinity; + private _maxRenderingWidth: number | undefined = Infinity; private readonly _onDidResize = new Emitter(); readonly onDidResize: Event = this._onDidResize.event; @@ -275,6 +279,8 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { } 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 @@ -290,7 +296,8 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { // this.element.eastSash.el.style.top = TOTAL_BORDER_WIDTH + 'px'; // Fire the current dimension - this._onDidResize.fire({ dimension: this._size, done: false }); + // 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(); diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 3e8a2c0e20c22..b4609fadcc73c 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -3,42 +3,504 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; +import * as dom from 'vs/base/browser/dom'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Position } from 'vs/editor/common/core/position'; +import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContentHoverVisibleData } from 'vs/editor/contrib/hover/browser/contentHover'; +import { PositionAffinity } from 'vs/editor/common/model'; +const SCROLLBAR_WIDTH = 10; -class ResizableHovertWidget extends ResizableWidget { +// TODO: maybe don't need the resizable widget class +class ResizableHoverWidget extends ResizableWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; - private _hoverDisposables = new DisposableStore(); + private hoverDisposables = new DisposableStore(); + // The ContentWidget is a child of the resizable widget + private resizableContentWidget: ResizableContentHoverWidget; - // TODO: Element from the abstract super class - // abstract properties have to be public? - resizableContentWidget: ResizableContentHoverWidget; + public readonly allowEditorOverflow = true; + public readonly _hover: HoverWidget = this.hoverDisposables.add(new HoverWidget()); + private readonly editor: ICodeEditor; + private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); + private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); + private readonly _focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); + private readonly _horizontalScrollingBy: number = 30; + private _visibleData: ContentHoverVisibleData | null = null; + private _renderingAbove: ContentWidgetPositionPreference; constructor( - editor: ICodeEditor + editor: ICodeEditor, + @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { super(editor, new MultipleSizePersistingOptions()); + this.editor = editor; // create here the dom node and all other logic should go here that was in the super abstract class this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); + this._renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - // element is a property of the resizable hover widget - this._hoverDisposables.add(this.element.onDidResize((e) => { + this.hoverDisposables.add(this.element.onDidResize((e) => { // When the resizable hover overlay changes, resize the widget // this._widget.resize(e.dimension); })); + + this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); + this.hoverDisposables.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { + this._updateFont(); + } + })); + this._setVisibleData(null); + this._layout(); + + this.hoverDisposables.add(this._focusTracker.onDidFocus(() => { + this._hoverFocusedKey.set(true); + })); + this.hoverDisposables.add(this._focusTracker.onDidBlur(() => { + this._hoverFocusedKey.set(false); + })); + + dom.append(this.element.domNode, this._hover.containerDomNode); + } + + + // -- decide what should be in the resizable content widget and what should be in the disposable hover widget + + + public get position(): Position | null { + return this._visibleData?.showAtPosition ?? null; + } + + public get isColorPickerVisible(): boolean { + return Boolean(this._visibleData?.colorPicker); + } + + public get isVisibleFromKeyboard(): boolean { + return (this._visibleData?.source === HoverStartSource.Keyboard); + } + + public get isVisible(): boolean { + return this._hoverVisibleKey.get() ?? false; + } + + public get renderingAbove(): ContentWidgetPositionPreference { + return this._renderingAbove; + } + + public set renderingAbove(renderingAbove: ContentWidgetPositionPreference) { + this._renderingAbove = renderingAbove; + } + + // NEW + public override resize(size: dom.Dimension) { + // Removing the max height and max width here - the max size is controlled by the resizable overlay + this._hover.contentsDomNode.style.maxHeight = 'none'; + this._hover.contentsDomNode.style.maxWidth = 'none'; + + const width = size.width + 'px'; + // const width = size.width - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; + this._hover.containerDomNode.style.width = width; + this._hover.contentsDomNode.style.width = width; + // const height = size.height - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; + const height = size.height + 'px'; + this._hover.containerDomNode.style.height = height; + this._hover.contentsDomNode.style.height = height; + + const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + if (hasHorizontalScrollbar) { + // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible + const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; + if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; + } + this._hover.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + } + + this._hover.scrollbar.scanDomNode(); + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + } + + // NEW + public override findMaximumRenderingHeight(): number | undefined { // rendering: ContentWidgetPositionPreference + + if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); + const bodyBox = dom.getClientArea(document.body); + let availableSpace: number; + + if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { + availableSpace = editorBox.top + mouseBox.top - 30; + } else { + const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; + availableSpace = bodyBox.height - mouseBottom; + } + + let divMaxHeight = 0; + for (const childHtmlElement of this._hover.contentsDomNode.children) { + divMaxHeight += childHtmlElement.clientHeight; + } + + if (this._hover.contentsDomNode.clientWidth < this._hover.contentsDomNode.scrollWidth) { + divMaxHeight += SCROLLBAR_WIDTH; + } + + return Math.min(availableSpace, divMaxHeight); + } + + // NEW + public findMaxRenderingWidth(): number | undefined { + if (!this.editor || !this.editor.hasModel()) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const widthOfEditor = editorBox.width; + const leftOfEditor = editorBox.left; + const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; + const leftOfContainer = this._hover.containerDomNode.offsetLeft; + return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; + } + + public override dispose(): void { + this.editor.removeContentWidget(this.resizableContentWidget); + if (this._visibleData) { + this._visibleData.disposables.dispose(); + } + super.dispose(); + } + + // Needs to be updated in the resizableContentWidget + public getPosition(): IContentWidgetPosition | null { + if (!this._visibleData) { + return null; + } + let preferAbove = this._visibleData.preferAbove; + if (!preferAbove && this._contextKeyService.getContextKeyValue(SuggestContext.Visible.key)) { + // Prefer rendering above if the suggest widget is visible + preferAbove = true; + } + + // :before content can align left of the text content + const affinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + + return { + position: this._visibleData.showAtPosition, + secondaryPosition: this._visibleData.showAtSecondaryPosition, + preference: ([this._renderingAbove]), + positionAffinity: affinity + }; + } + + public getDomNode() { + return this._hover.containerDomNode; + } + + public getContentDomNode() { + return this._hover.contentsDomNode; + } + + public isMouseGettingCloser(posx: number, posy: number): boolean { + if (!this._visibleData) { + return false; + } + if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { + this._visibleData.initialMousePosX = posx; + this._visibleData.initialMousePosY = posy; + return false; + } + + const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); + if (typeof this._visibleData.closestMouseDistance === 'undefined') { + this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + } + const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + // The mouse is getting farther away + return false; + } + this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); + return true; + } + + private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { + if (this._visibleData) { + this._visibleData.disposables.dispose(); + } + this._visibleData = visibleData; + this._hoverVisibleKey.set(!!this._visibleData); + this._hover.containerDomNode.classList.toggle('hidden', !this._visibleData); + } + + private _layout(): void { + const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); + const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); + + this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; + this._hover.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + this._hover.contentsDomNode.style.maxHeight = `${height}px`; + this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; } + + private _updateFont(): void { + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); + codeClasses.forEach(node => this.editor.applyFontInfo(node)); + } + + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData, persistedSize: dom.Dimension | undefined): void { + + if (!this.editor || !this.editor.hasModel()) { + return; + } + + this._setVisibleData(visibleData); + + this._hover.contentsDomNode.textContent = ''; + this._hover.contentsDomNode.appendChild(node); + this._hover.contentsDomNode.style.paddingBottom = ''; + this._updateFont(); + + const containerDomNode = this.resizableContentWidget.getDomNode(); + let height; + + // If the persisted size has already been found then set a maximum height and width + if (!persistedSize) { + this._hover.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this.onContentsChanged(); + + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this.editor.render(); + height = containerDomNode.clientHeight; + } + // When there is a persisted size then do not use a maximum height or width + else { + this._hover.contentsDomNode.style.maxHeight = 'none'; + this._hover.contentsDomNode.style.maxWidth = 'none'; + height = persistedSize.height; + } + + // The dimensions of the document in which we are displaying the hover + const bodyBox = dom.getClientArea(document.body); + // Hard-coded in the hover.css file as 1.5em or 24px + const minHeight = 24; + // The full height is already passed in as a parameter + const fullHeight = height; + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); + // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height + const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; + // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position + const availableSpaceBelow = bodyBox.height - mouseBottom; + // Max height below is the minimum of the available space below and the full height of the widget + const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); + // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor + const availableSpaceAbove = editorBox.top + mouseBox.top - 30; + const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); + // We find the maximum height of the widget possible on the top or on the bottom + const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); + + if (height < minHeight) { + height = minHeight; + } + if (height > maxHeight) { + height = maxHeight; + } + + // Determining whether we should render above or not ideally + if (this.editor.getOption(EditorOption.hover).above) { + this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + } else { + this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + } + + // See https://github.com/microsoft/vscode/issues/140339 + // TODO: Doing a second layout of the hover after force rendering the editor + if (!persistedSize) { + this.onContentsChanged(); + } + + if (visibleData.stoleFocus) { + this._hover.containerDomNode.focus(); + } + visibleData.colorPicker?.layout(); + + + if (!this._visibleData) { + return; + } + + + this.resizableContentWidget.position = this._visibleData.showAtPosition; + this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; + this.resizableContentWidget.preference = [this._renderingAbove]; + this.resizableContentWidget.positionAffinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + } + + public override hide(): void { + this.element.clearSashHoverState(); + if (this._visibleData) { + const stoleFocus = this._visibleData.stoleFocus; + this._setVisibleData(null); + this.editor.layoutContentWidget(this.resizableContentWidget); + if (stoleFocus) { + this.editor.focus(); + } + } + } + + // NEW + /* + public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { + + const containerDomNode = this.resizableContentWidget.getDomNode(); + const contentsDomNode = this.resizableContentWidget.getContentsDomNode(); + + // Suppose a persisted size is defined + if (persistedSize) { + + const widthMinusSash = Math.min(this.findMaxRenderingWidth() ?? Infinity, persistedSize.width - SASH_WIDTH); + const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); + + // Already setting directly the height and width parameters + containerDomNode.style.width = widthMinusSash + 'px'; + containerDomNode.style.height = heightMinusSash + 'px'; + contentsDomNode.style.width = widthMinusSash + 'px'; + contentsDomNode.style.height = heightMinusSash + 'px'; + + } else { + + // Otherwise the height and width are set to auto + containerDomNode.style.width = 'auto'; + containerDomNode.style.height = 'auto'; + contentsDomNode.style.width = 'auto'; + contentsDomNode.style.height = 'auto'; + } + + this.editor.layoutContentWidget(this); + this._hover.onContentsChanged(); + + const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + if (hasHorizontalScrollbar) { + // There is just a horizontal scrollbar + const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; + let reposition = false; + if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; + reposition = true; + } + const maxRenderingHeight = this.findMaxRenderingHeight(this._renderingAbove); + // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. + if (persistedSize && maxRenderingHeight) { + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SASH_WIDTH) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SASH_WIDTH - SCROLLBAR_WIDTH) + 'px'; + reposition = true; + } + if (reposition) { + this.editor.layoutContentWidget(this); + this._hover.onContentsChanged(); + } + } + }*/ + + // OLD FUNCTION + public onContentsChanged(): void { + this.editor.layoutContentWidget(this.resizableContentWidget); + this._hover.onContentsChanged(); + + const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + if (hasHorizontalScrollbar) { + // There is just a horizontal scrollbar + const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; + if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; + this.editor.layoutContentWidget(this.resizableContentWidget); + this._hover.onContentsChanged(); + } + } + } + + public clear(): void { + this._hover.contentsDomNode.textContent = ''; + } + + public focus(): void { + this._hover.containerDomNode.focus(); + } + + public scrollUp(): void { + const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); + } + + public scrollDown(): void { + const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); + } + + public scrollLeft(): void { + const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; + this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); + } + + public scrollRight(): void { + const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; + this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); + } + + public pageUp(): void { + const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; + this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); + } + + public pageDown(): void { + const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; + this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); + } + + public goToTop(): void { + this._hover.scrollbar.setScrollPosition({ scrollTop: 0 }); + } + + public goToBottom(): void { + this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); + } + + public escape(): void { + this.editor.focus(); + } + + // -- decide what should be in the resizable content widget and what should be in the disposable hover widget } class ResizableContentHoverWidget extends ResizableContentWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; - private _hoverDisposables = new DisposableStore(); + private hoverDisposables = new DisposableStore(); - constructor(resizableHoverWidget: ResizableHovertWidget, editor: ICodeEditor) { + constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget, editor); } } +function computeDistanceFromPointToRectangle(initialMousePosX: number, initialMousePosY: number, left: number, top: number, width: number, height: number): number | undefined { + throw new Error('Function not implemented.'); +} + From 642b2089eccf88da3c3ab294d1ce7c1e2fef1e25 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 17:55:08 +0200 Subject: [PATCH 04/72] commenting some method --- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index b4609fadcc73c..fb7c93a65b3ca 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -182,6 +182,7 @@ class ResizableHoverWidget extends ResizableWidget { } // Needs to be updated in the resizableContentWidget + /* public getPosition(): IContentWidgetPosition | null { if (!this._visibleData) { return null; @@ -202,6 +203,7 @@ class ResizableHoverWidget extends ResizableWidget { positionAffinity: affinity }; } + */ public getDomNode() { return this._hover.containerDomNode; From 17ca49d39073a46e851b76f55ccad2ac0084a9f1 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:07:10 +0200 Subject: [PATCH 05/72] removed some of the errors appearing, verify it all works later --- .../contrib/hover/browser/contentHover.ts | 11 +++--- .../hover/browser/resizableContentWidget.ts | 8 ++++ .../hover/browser/resizableHoverWidget.ts | 38 +++---------------- 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index dd3367e423118..2a7e7bf1acae9 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -24,17 +24,15 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest'; import { AsyncIterableObject } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - // TODO: instead of making an instance of the content hover widget, make an instance of the resizable content hover widget - private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); - - // TODO: private readonly _resizableOverlay = this._register(this._instantiationService.createInstance(ResizableContentHoverWidget, this._editor)); - + // TODO: Initial, private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); + private readonly _widget; private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; @@ -47,6 +45,7 @@ export class ContentHoverController extends Disposable { ) { super(); + this._widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; for (const participant of HoverParticipantRegistry.getAll()) { @@ -819,7 +818,7 @@ class ContentHoverComputer implements IHoverComputer { } } -function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { +export function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { const x = (left + width / 2); // x center of rectangle const y = (top + height / 2); // y center of rectangle const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 9f1599487fe38..8195ced672163 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -65,6 +65,10 @@ export abstract class ResizableWidget implements IDisposable { findMaximumRenderingWidth(): number | undefined { return Infinity; } + + findPersistedSize(): dom.Dimension | undefined { + return this._persistingMechanism.findSize(); + } } export abstract class ResizableContentWidget implements IContentWidget { @@ -80,6 +84,10 @@ export abstract class ResizableContentWidget implements IContentWidget { this.editor.addContentWidget(this); } + findPersistedSize(): dom.Dimension | undefined { + return this.resizableWidget.findPersistedSize(); + } + getId(): string { return this.ID; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index fb7c93a65b3ca..849f4d76e5ac6 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -13,13 +13,13 @@ import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config import { Position } from 'vs/editor/common/core/position'; import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ContentHoverVisibleData } from 'vs/editor/contrib/hover/browser/contentHover'; +import { ContentHoverVisibleData, computeDistanceFromPointToRectangle } from 'vs/editor/contrib/hover/browser/contentHover'; import { PositionAffinity } from 'vs/editor/common/model'; const SCROLLBAR_WIDTH = 10; // TODO: maybe don't need the resizable widget class -class ResizableHoverWidget extends ResizableWidget { +export class ResizableHoverWidget extends ResizableWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); @@ -181,30 +181,6 @@ class ResizableHoverWidget extends ResizableWidget { super.dispose(); } - // Needs to be updated in the resizableContentWidget - /* - public getPosition(): IContentWidgetPosition | null { - if (!this._visibleData) { - return null; - } - let preferAbove = this._visibleData.preferAbove; - if (!preferAbove && this._contextKeyService.getContextKeyValue(SuggestContext.Visible.key)) { - // Prefer rendering above if the suggest widget is visible - preferAbove = true; - } - - // :before content can align left of the text content - const affinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - - return { - position: this._visibleData.showAtPosition, - secondaryPosition: this._visibleData.showAtSecondaryPosition, - preference: ([this._renderingAbove]), - positionAffinity: affinity - }; - } - */ - public getDomNode() { return this._hover.containerDomNode; } @@ -260,7 +236,9 @@ class ResizableHoverWidget extends ResizableWidget { codeClasses.forEach(node => this.editor.applyFontInfo(node)); } - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData, persistedSize: dom.Dimension | undefined): void { + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + + const persistedSize = this.findPersistedSize(); if (!this.editor || !this.editor.hasModel()) { return; @@ -493,7 +471,7 @@ class ResizableHoverWidget extends ResizableWidget { // -- decide what should be in the resizable content widget and what should be in the disposable hover widget } -class ResizableContentHoverWidget extends ResizableContentWidget { +export class ResizableContentHoverWidget extends ResizableContentWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); @@ -502,7 +480,3 @@ class ResizableContentHoverWidget extends ResizableContentWidget { super(resizableHoverWidget, editor); } } -function computeDistanceFromPointToRectangle(initialMousePosX: number, initialMousePosY: number, left: number, top: number, width: number, height: number): number | undefined { - throw new Error('Function not implemented.'); -} - From 3687cff8450202fb374e0694f19f1b578a8a70bc Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:09:13 +0200 Subject: [PATCH 06/72] resolving the cyclic dependency, the hover no longer appears, find out why --- .../hover/browser/resizableHoverWidget.ts | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 849f4d76e5ac6..b3f2da64c912f 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -13,8 +13,8 @@ import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config import { Position } from 'vs/editor/common/core/position'; import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ContentHoverVisibleData, computeDistanceFromPointToRectangle } from 'vs/editor/contrib/hover/browser/contentHover'; import { PositionAffinity } from 'vs/editor/common/model'; +import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; const SCROLLBAR_WIDTH = 10; @@ -480,3 +480,29 @@ export class ResizableContentHoverWidget extends ResizableContentWidget { super(resizableHoverWidget, editor); } } + +export class ContentHoverVisibleData { + + public closestMouseDistance: number | undefined = undefined; + + constructor( + public readonly colorPicker: IEditorHoverColorPickerWidget | null, + public readonly showAtPosition: Position, + public readonly showAtSecondaryPosition: Position, + public readonly preferAbove: boolean, + public readonly stoleFocus: boolean, + public readonly source: HoverStartSource, + public readonly isBeforeContent: boolean, + public initialMousePosX: number | undefined, + public initialMousePosY: number | undefined, + public readonly disposables: DisposableStore + ) { } +} + +export function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { + const x = (left + width / 2); // x center of rectangle + const y = (top + height / 2); // y center of rectangle + const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); + const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); + return Math.sqrt(dx * dx + dy * dy); +} From 4d130193684abb92a6fc62097de0669bcf5fb32c Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:10:32 +0200 Subject: [PATCH 07/72] cleaning the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 6 +++--- src/vs/editor/contrib/suggest/browser/suggestController.ts | 2 -- src/vs/editor/contrib/suggest/browser/suggestWidget.ts | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 2a7e7bf1acae9..e16652c594cfb 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -31,7 +31,7 @@ const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - // TODO: Initial, private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); + // TODO: Initially, private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); private readonly _widget; private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; @@ -422,7 +422,7 @@ class FilteredHoverResult extends HoverResult { } } -export class ContentHoverVisibleData { +class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; @@ -818,7 +818,7 @@ class ContentHoverComputer implements IHoverComputer { } } -export function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { +function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { const x = (left + width / 2); // x center of rectangle const y = (top + height / 2); // y center of rectangle const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index ed994e029dcb3..abd5d8b23bb7c 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -144,8 +144,6 @@ export class SuggestController implements IEditorContribution { this.widget = this._toDispose.add(new IdleValue(() => { - // TODO: The point where the suggest widget instance is created - // TODO: suggest widget should be mapped to the content hover widget const widget = this._instantiationService.createInstance(SuggestWidget, this.editor); this._toDispose.add(widget); diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index d30d9b3f51a2d..d2e86783c8a0f 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -96,7 +96,6 @@ class PersistedWidgetSize { } } -// TODO: The suggest widget is a disposable and it can be instantiated export class SuggestWidget implements IDisposable { private static LOADING_MESSAGE: string = nls.localize('suggestWidget.loading', "Loading..."); @@ -922,7 +921,6 @@ export class SuggestWidget implements IDisposable { } } -// TODO: The suggest content widget is a content widget and it belongs to the suggest widget export class SuggestContentWidget implements IContentWidget { readonly allowEditorOverflow = true; From 27c777e7ddec69d66aed64804d8b35846380149b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:13:01 +0200 Subject: [PATCH 08/72] made sashes red in order to be able to debug --- src/vs/base/browser/ui/sash/sash.css | 2 +- src/vs/editor/contrib/hover/browser/contentHover.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.css b/src/vs/base/browser/ui/sash/sash.css index fdcbc26609e07..40bd11fe8017d 100644 --- a/src/vs/base/browser/ui/sash/sash.css +++ b/src/vs/base/browser/ui/sash/sash.css @@ -107,7 +107,7 @@ position: absolute; width: 100%; height: 100%; - background: transparent; + background: red; } .monaco-workbench:not(.reduce-motion) .monaco-sash:before { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index e16652c594cfb..c08501061c6f3 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -31,7 +31,7 @@ const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - // TODO: Initially, private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); + // INITIALLY: private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); private readonly _widget; private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; From b7c313b0d718ddd3e97184479d94a8aa9f9935d9 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:42:18 +0200 Subject: [PATCH 09/72] adding the content widget inside of showAt in order to have the content widget appear, now need to resize is correctly --- .../hover/browser/resizableContentWidget.css | 3 +- .../hover/browser/resizableContentWidget.ts | 34 +++++++----- .../hover/browser/resizableHoverWidget.ts | 52 +++++++++++-------- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.css b/src/vs/editor/contrib/hover/browser/resizableContentWidget.css index 48840ea0931df..70e6b2fbe6eb6 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.css +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.css @@ -5,6 +5,5 @@ .monaco-editor .resizable-widget { z-index: 40; - display: flex; - flex-direction: column; + display: block; } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 8195ced672163..a5bf04b1295bb 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -15,28 +15,22 @@ import { clamp } from 'vs/base/common/numbers'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Emitter, Event } from 'vs/base/common/event'; -// TODO: need several types of constructors depending on what kind of resizable element we will be creating export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; - // readonly _domNode: HTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; - // TODO: do I need this? - // private _renderingAbove: ContentWidgetPositionPreference = ContentWidgetPositionPreference.ABOVE; - 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'); - // TODO: setting the resizable widget to this instance like for the suggest widget - // TODO: this._resizableContentWidget.resizableWidget = this; - // TODO: this._domNode = dom.append(this.element.domNode, this._contents); - if (this._persistingOptions instanceof SingleSizePersistingOptions) { this._persistingMechanism = new SingleSizePersistingMechanism(this, this.element, this._editor, this._persistingOptions); } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { @@ -51,8 +45,7 @@ export abstract class ResizableWidget implements IDisposable { this.element.dispose(); } - resize(dimension: dom.Dimension): void { - } + resize(dimension: dom.Dimension): void { } hide(): void { this.element.clearSashHoverState(); @@ -73,7 +66,6 @@ export abstract class ResizableWidget implements IDisposable { export abstract class ResizableContentWidget implements IContentWidget { - // Previously was a static variable now it is a private one abstract ID: string; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; @@ -82,6 +74,7 @@ export abstract class ResizableContentWidget implements IContentWidget { constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { this.editor.addContentWidget(this); + console.log('Inisde of ResizableContentWidget constructor'); } findPersistedSize(): dom.Dimension | undefined { @@ -89,20 +82,30 @@ export abstract class ResizableContentWidget implements IContentWidget { } 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 { - return { + + 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 { @@ -144,6 +147,7 @@ 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; @@ -185,7 +189,6 @@ class SingleSizePersistingMechanism implements IPersistingMechanism { return; } - // TODO: maybe need to make more generic, this is specific to the suggest widget if (state) { const fontInfo = this.editor.getOption(EditorOption.fontInfo); const itemHeight = clamp(this.editor.getOption(EditorOption.suggestLineHeight) || fontInfo.lineHeight, 8, 1000); @@ -357,6 +360,9 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { } findSize(): dom.Dimension | undefined { + + console.log('Inside of findSize of the MultiplePersistingMechanisms'); + if (!this._tooltipPosition || !this.editor.hasModel()) { return; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index b3f2da64c912f..a68d8529ec475 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -71,10 +71,6 @@ export class ResizableHoverWidget extends ResizableWidget { dom.append(this.element.domNode, this._hover.containerDomNode); } - - // -- decide what should be in the resizable content widget and what should be in the disposable hover widget - - public get position(): Position | null { return this._visibleData?.showAtPosition ?? null; } @@ -101,6 +97,8 @@ export class ResizableHoverWidget extends ResizableWidget { // NEW public override resize(size: dom.Dimension) { + console.log('Inside of resize'); + // Removing the max height and max width here - the max size is controlled by the resizable overlay this._hover.contentsDomNode.style.maxHeight = 'none'; this._hover.contentsDomNode.style.maxWidth = 'none'; @@ -130,8 +128,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.editor.render(); } - // NEW - public override findMaximumRenderingHeight(): number | undefined { // rendering: ContentWidgetPositionPreference + public override findMaximumRenderingHeight(): number | undefined { if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { return; @@ -160,7 +157,6 @@ export class ResizableHoverWidget extends ResizableWidget { return Math.min(availableSpace, divMaxHeight); } - // NEW public findMaxRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; @@ -185,7 +181,7 @@ export class ResizableHoverWidget extends ResizableWidget { return this._hover.containerDomNode; } - public getContentDomNode() { + public getContentsDomNode() { return this._hover.contentsDomNode; } @@ -238,6 +234,8 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + this.editor.addContentWidget(this.resizableContentWidget); + const persistedSize = this.findPersistedSize(); if (!this.editor || !this.editor.hasModel()) { @@ -327,6 +325,10 @@ export class ResizableHoverWidget extends ResizableWidget { this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this._renderingAbove]; this.resizableContentWidget.positionAffinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + console.log('At the end of showAt'); } public override hide(): void { @@ -342,17 +344,20 @@ export class ResizableHoverWidget extends ResizableWidget { } // NEW - /* + public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { - const containerDomNode = this.resizableContentWidget.getDomNode(); - const contentsDomNode = this.resizableContentWidget.getContentsDomNode(); + console.log('Inside of onContentsChanged'); + + const containerDomNode = this.getDomNode(); + const contentsDomNode = this.getContentsDomNode(); // Suppose a persisted size is defined if (persistedSize) { - const widthMinusSash = Math.min(this.findMaxRenderingWidth() ?? Infinity, persistedSize.width - SASH_WIDTH); - const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); + const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width); // - SASH_WIDTH + // const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); + const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height); // SASH_WIDTH // Already setting directly the height and width parameters containerDomNode.style.width = widthMinusSash + 'px'; @@ -369,7 +374,7 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.height = 'auto'; } - this.editor.layoutContentWidget(this); + this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); @@ -382,21 +387,22 @@ export class ResizableHoverWidget extends ResizableWidget { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; reposition = true; } - const maxRenderingHeight = this.findMaxRenderingHeight(this._renderingAbove); + const maxRenderingHeight = this.findMaximumRenderingHeight(); // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. if (persistedSize && maxRenderingHeight) { - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SASH_WIDTH) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SASH_WIDTH - SCROLLBAR_WIDTH) + 'px'; + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height) + 'px'; // - SASH_WIDTH + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SCROLLBAR_WIDTH) + 'px'; // - SASH_WIDTH reposition = true; } if (reposition) { - this.editor.layoutContentWidget(this); + this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); } } - }*/ + } // OLD FUNCTION + /* public onContentsChanged(): void { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); @@ -413,6 +419,7 @@ export class ResizableHoverWidget extends ResizableWidget { } } } + */ public clear(): void { this._hover.contentsDomNode.textContent = ''; @@ -467,8 +474,6 @@ export class ResizableHoverWidget extends ResizableWidget { public escape(): void { this.editor.focus(); } - - // -- decide what should be in the resizable content widget and what should be in the disposable hover widget } export class ResizableContentHoverWidget extends ResizableContentWidget { @@ -478,10 +483,11 @@ export class ResizableContentHoverWidget extends ResizableContentWidget { constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget, editor); + console.log('Inside of resizable content hover widget'); } } -export class ContentHoverVisibleData { +class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; @@ -499,7 +505,7 @@ export class ContentHoverVisibleData { ) { } } -export function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { +function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { const x = (left + width / 2); // x center of rectangle const y = (top + height / 2); // y center of rectangle const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); From 3ed8eae2ca8a892c7f3f77a2eabce1928d0afe1b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:47:31 +0200 Subject: [PATCH 10/72] now we see the red sash after changing the layout --- src/vs/editor/contrib/hover/browser/resizableContentWidget.ts | 2 +- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index a5bf04b1295bb..72f2bacb7ab57 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -91,7 +91,7 @@ export abstract class ResizableContentWidget implements IContentWidget { 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'; + // this.resizableWidget.element.domNode.style.display = 'block'; return this.resizableWidget.element.domNode; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index a68d8529ec475..abe56c30a5b16 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -321,6 +321,9 @@ export class ResizableHoverWidget extends ResizableWidget { } + const clientHeight = this._hover.containerDomNode.clientHeight; + const clientWidth = this._hover.containerDomNode.clientWidth; + this.element.layout(clientHeight, clientWidth); this.resizableContentWidget.position = this._visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this._renderingAbove]; From 7d65d198f9a7d2768c5dc7026e30554a3bf707e7 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:48:34 +0200 Subject: [PATCH 11/72] also adding the layxout of the element into the onContentsChanges function --- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index abe56c30a5b16..454ef817a9501 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -380,6 +380,10 @@ export class ResizableHoverWidget extends ResizableWidget { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); + const clientHeight = this._hover.containerDomNode.clientHeight; + const clientWidth = this._hover.containerDomNode.clientWidth; + this.element.layout(clientHeight, clientWidth); + const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { From a5e5f8dd59902a250646477cd2e982ec0af8ac60 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:52:23 +0200 Subject: [PATCH 12/72] find out why the widget disappears when you hover on it, simplify further the code --- .../contrib/hover/browser/resizableContentWidget.css | 9 --------- .../editor/contrib/hover/browser/resizableHoverWidget.ts | 3 ++- 2 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 src/vs/editor/contrib/hover/browser/resizableContentWidget.css diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.css b/src/vs/editor/contrib/hover/browser/resizableContentWidget.css deleted file mode 100644 index 70e6b2fbe6eb6..0000000000000 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.css +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.monaco-editor .resizable-widget { - z-index: 40; - display: block; -} diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 454ef817a9501..81cc3132e0bbd 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -49,7 +49,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverDisposables.add(this.element.onDidResize((e) => { // When the resizable hover overlay changes, resize the widget - // this._widget.resize(e.dimension); + this.resize(e.dimension); })); this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); @@ -336,6 +336,7 @@ export class ResizableHoverWidget extends ResizableWidget { public override hide(): void { this.element.clearSashHoverState(); + this.editor.removeContentWidget(this.resizableContentWidget); if (this._visibleData) { const stoleFocus = this._visibleData.stoleFocus; this._setVisibleData(null); From 9dc9fe7e7006516b54f360f2b25bc155003ad814 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 31 Mar 2023 18:54:07 +0200 Subject: [PATCH 13/72] first simplify maximally and clean the code, then extract the common factors into an inteface --- src/vs/editor/contrib/hover/browser/contentHover.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index c08501061c6f3..77b597d9364e7 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -31,7 +31,6 @@ const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - // INITIALLY: private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); private readonly _widget; private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; From 41d4ad30c137d7a4e013ba769f20ba032dc4a5f7 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 09:46:18 +0200 Subject: [PATCH 14/72] changing the code so that hover does not disappear on hovering on the content widget of the resizable hover widget --- .../editor/contrib/hover/browser/contentHover.ts | 5 +++++ src/vs/editor/contrib/hover/browser/hover.ts | 15 +++++++++++++-- .../hover/browser/resizableContentWidget.ts | 1 + .../contrib/hover/browser/resizableHoverWidget.ts | 12 +++++++++--- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 77b597d9364e7..b10d1239fdd1e 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -143,6 +143,7 @@ export class ContentHoverController extends Disposable { } if (!anchor) { + console.log('When anchor is false'); this._setCurrentResult(null); return false; } @@ -154,6 +155,7 @@ export class ContentHoverController extends Disposable { if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { // The new anchor is not compatible with the previous anchor + console.log('When canAdoptVisibleHover is false'); this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); return true; @@ -181,6 +183,7 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { + console.log('Inside of _setCurrentResult'); if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -189,6 +192,7 @@ export class ContentHoverController extends Disposable { hoverResult = null; } this._currentResult = hoverResult; + console.log('this._currentResult', this._currentResult); if (this._currentResult) { this._renderMessages(this._currentResult.anchor, this._currentResult.messages); } else { @@ -197,6 +201,7 @@ export class ContentHoverController extends Disposable { } public hide(): void { + console.log('Inisde of hide of the ContentHoverController'); this._computer.anchor = null; this._hoverOperation.cancel(); this._setCurrentResult(null); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 10df5c935132a..aef93031843af 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -30,6 +30,7 @@ import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/browser/markerHo import 'vs/css!./hover'; import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineSuggestionHintsWidget'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; export class ModesHoverController implements IEditorContribution { @@ -163,8 +164,18 @@ export class ModesHoverController implements IEditorContribution { return; } - if (this._isHoverSticky && target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID) { - // mouse moved on top of overlay hover widget + console.log('Inside of _onEditorMouseMove'); + console.log('target.detail: ', target.detail); + + if (target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID) { + console.log('Insid of first if loop'); + // mouse down on top of overlay margin hover widget + return; + } + + if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { + console.log('Inside of the second if loop'); + // mouse down on top of the overlay hover widget return; } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 72f2bacb7ab57..f583c3e12ad1f 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -109,6 +109,7 @@ export abstract class ResizableContentWidget implements IContentWidget { } hide(): void { + console.log('Inside of hide of the ResizableContentWidget'); this.editor.layoutContentWidget(this); } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 81cc3132e0bbd..f4d2391dedbaf 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -21,7 +21,7 @@ const SCROLLBAR_WIDTH = 10; // TODO: maybe don't need the resizable widget class export class ResizableHoverWidget extends ResizableWidget { - public ID = 'editor.contrib.resizableContentHoverWidget'; + public static ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); // The ContentWidget is a child of the resizable widget private resizableContentWidget: ResizableContentHoverWidget; @@ -335,6 +335,7 @@ export class ResizableHoverWidget extends ResizableWidget { } public override hide(): void { + console.log('Inside of hide of ResizableHoverWidget'); this.element.clearSashHoverState(); this.editor.removeContentWidget(this.resizableContentWidget); if (this._visibleData) { @@ -383,11 +384,15 @@ export class ResizableHoverWidget extends ResizableWidget { const clientHeight = this._hover.containerDomNode.clientHeight; const clientWidth = this._hover.containerDomNode.clientWidth; - this.element.layout(clientHeight, clientWidth); + this.element.layout(clientHeight + 8, clientWidth + 8); + // this.element.layout(clientHeight, clientWidth); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { + console.log('hasHorizontalScrollbar: ', hasHorizontalScrollbar); + + // if (hasHorizontalScrollbar) { + if (false) { // There is just a horizontal scrollbar const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; @@ -404,6 +409,7 @@ export class ResizableHoverWidget extends ResizableWidget { } if (reposition) { this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); this._hover.onContentsChanged(); } } From 8f94decf47e2a6b25c5f36bbd511493722df0a45 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 10:02:44 +0200 Subject: [PATCH 15/72] saving the changes --- src/vs/editor/contrib/hover/browser/contentHover.ts | 5 ----- src/vs/editor/contrib/hover/browser/hover.ts | 5 ----- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 5 +++++ 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index b10d1239fdd1e..77b597d9364e7 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -143,7 +143,6 @@ export class ContentHoverController extends Disposable { } if (!anchor) { - console.log('When anchor is false'); this._setCurrentResult(null); return false; } @@ -155,7 +154,6 @@ export class ContentHoverController extends Disposable { if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { // The new anchor is not compatible with the previous anchor - console.log('When canAdoptVisibleHover is false'); this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); return true; @@ -183,7 +181,6 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { - console.log('Inside of _setCurrentResult'); if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -192,7 +189,6 @@ export class ContentHoverController extends Disposable { hoverResult = null; } this._currentResult = hoverResult; - console.log('this._currentResult', this._currentResult); if (this._currentResult) { this._renderMessages(this._currentResult.anchor, this._currentResult.messages); } else { @@ -201,7 +197,6 @@ export class ContentHoverController extends Disposable { } public hide(): void { - console.log('Inisde of hide of the ContentHoverController'); this._computer.anchor = null; this._hoverOperation.cancel(); this._setCurrentResult(null); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index aef93031843af..ee941d4ac6145 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -164,17 +164,12 @@ export class ModesHoverController implements IEditorContribution { return; } - console.log('Inside of _onEditorMouseMove'); - console.log('target.detail: ', target.detail); - if (target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID) { - console.log('Insid of first if loop'); // mouse down on top of overlay margin hover widget return; } if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { - console.log('Inside of the second if loop'); // mouse down on top of the overlay hover widget return; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index f4d2391dedbaf..85257054b63f9 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -234,6 +234,11 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + this.resizableContentWidget.position = visibleData.showAtPosition; + this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; + this.resizableContentWidget.preference = [this._renderingAbove]; + this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); From 4b5622ea55980a337accab18be8e4003f3958878 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 12:34:42 +0200 Subject: [PATCH 16/72] does no longer automatically disappear on sash click --- .../contrib/hover/browser/contentHover.ts | 10 + src/vs/editor/contrib/hover/browser/hover.ts | 4 +- .../hover/browser/resizableContentWidget.ts | 13 + .../hover/browser/resizableHoverWidget.ts | 224 +++++++++--------- 4 files changed, 134 insertions(+), 117 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 77b597d9364e7..95db16377f5c6 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -76,10 +76,20 @@ export class ContentHoverController extends Disposable { })); } + get widget() { + return this._widget; + } + /** * Returns true if the hover shows now or will show. */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { + + // While the hover overlay is resizing, the hover is showing + if (this._widget.isResizing()) { + return true; + } + const anchorCandidates: HoverAnchor[] = []; for (const participant of this._participants) { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index ee941d4ac6145..445d315ba7d9a 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -227,7 +227,9 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); - this._contentWidget?.hide(); + if (!this._contentWidget?.widget.isResizing()) { + this._contentWidget?.hide(); + } } private _getOrCreateContentWidget(): ContentHoverController { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index f583c3e12ad1f..8fda53425a176 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -20,6 +20,7 @@ export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; + private resizing: boolean = false; constructor( private readonly _editor: ICodeEditor, @@ -38,6 +39,17 @@ export abstract class ResizableWidget implements IDisposable { } else { throw new Error('Please specify a valid persisting mechanism'); } + + this._disposables.add(this.element.onDidWillResize(() => { + this.resizing = true; + })); + this._disposables.add(this.element.onDidResize(() => { + this.resizing = false; + })); + } + + public isResizing() { + return this.resizing; } dispose(): void { @@ -48,6 +60,7 @@ export abstract class ResizableWidget implements IDisposable { resize(dimension: dom.Dimension): void { } hide(): void { + this.resizing = false; this.element.clearSashHoverState(); } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 85257054b63f9..0aeb689cf2ea2 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -5,7 +5,7 @@ import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ContentWidgetPositionPreference, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import * as dom from 'vs/base/browser/dom'; @@ -23,18 +23,17 @@ export class ResizableHoverWidget extends ResizableWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); - // The ContentWidget is a child of the resizable widget private resizableContentWidget: ResizableContentHoverWidget; + public readonly hoverWidget: HoverWidget = this.hoverDisposables.add(new HoverWidget()); public readonly allowEditorOverflow = true; - public readonly _hover: HoverWidget = this.hoverDisposables.add(new HoverWidget()); private readonly editor: ICodeEditor; - private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); - private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); - private readonly _focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); - private readonly _horizontalScrollingBy: number = 30; - private _visibleData: ContentHoverVisibleData | null = null; - private _renderingAbove: ContentWidgetPositionPreference; + private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); + private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); + private readonly focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); + private readonly horizontalScrollingBy: number = 30; + private visibleData: ContentHoverVisibleData | null = null; + private renderingAbove: ContentWidgetPositionPreference; constructor( editor: ICodeEditor, @@ -43,9 +42,8 @@ export class ResizableHoverWidget extends ResizableWidget { super(editor, new MultipleSizePersistingOptions()); this.editor = editor; - // create here the dom node and all other logic should go here that was in the super abstract class this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); - this._renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; this.hoverDisposables.add(this.element.onDidResize((e) => { // When the resizable hover overlay changes, resize the widget @@ -61,84 +59,78 @@ export class ResizableHoverWidget extends ResizableWidget { this._setVisibleData(null); this._layout(); - this.hoverDisposables.add(this._focusTracker.onDidFocus(() => { - this._hoverFocusedKey.set(true); + this.hoverDisposables.add(this.focusTracker.onDidFocus(() => { + this.hoverFocusedKey.set(true); })); - this.hoverDisposables.add(this._focusTracker.onDidBlur(() => { - this._hoverFocusedKey.set(false); + this.hoverDisposables.add(this.focusTracker.onDidBlur(() => { + this.hoverFocusedKey.set(false); })); - dom.append(this.element.domNode, this._hover.containerDomNode); + // containerDomNode added to the element dom node + // the element.domNode is returned by the getDomNode() of the ContentWidget + dom.append(this.element.domNode, this.hoverWidget.containerDomNode); } public get position(): Position | null { - return this._visibleData?.showAtPosition ?? null; + return this.visibleData?.showAtPosition ?? null; } public get isColorPickerVisible(): boolean { - return Boolean(this._visibleData?.colorPicker); + return Boolean(this.visibleData?.colorPicker); } public get isVisibleFromKeyboard(): boolean { - return (this._visibleData?.source === HoverStartSource.Keyboard); + return (this.visibleData?.source === HoverStartSource.Keyboard); } public get isVisible(): boolean { - return this._hoverVisibleKey.get() ?? false; + return this.hoverVisibleKey.get() ?? false; } - public get renderingAbove(): ContentWidgetPositionPreference { - return this._renderingAbove; - } - - public set renderingAbove(renderingAbove: ContentWidgetPositionPreference) { - this._renderingAbove = renderingAbove; - } - - // NEW public override resize(size: dom.Dimension) { console.log('Inside of resize'); // Removing the max height and max width here - the max size is controlled by the resizable overlay - this._hover.contentsDomNode.style.maxHeight = 'none'; - this._hover.contentsDomNode.style.maxWidth = 'none'; + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; const width = size.width + 'px'; + this.hoverWidget.containerDomNode.style.width = width; + this.hoverWidget.contentsDomNode.style.width = width; + const height = size.height + 'px'; + this.hoverWidget.containerDomNode.style.height = height; + this.hoverWidget.contentsDomNode.style.height = height; + // const width = size.width - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; - this._hover.containerDomNode.style.width = width; - this._hover.contentsDomNode.style.width = width; // const height = size.height - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; - const height = size.height + 'px'; - this._hover.containerDomNode.style.height = height; - this._hover.contentsDomNode.style.height = height; - const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible - const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; - if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - this._hover.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } - this._hover.scrollbar.scanDomNode(); + this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); } public override findMaximumRenderingHeight(): number | undefined { - if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { + if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); + const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; - if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { availableSpace = editorBox.top + mouseBox.top - 30; } else { const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; @@ -146,11 +138,11 @@ export class ResizableHoverWidget extends ResizableWidget { } let divMaxHeight = 0; - for (const childHtmlElement of this._hover.contentsDomNode.children) { + for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } - if (this._hover.contentsDomNode.clientWidth < this._hover.contentsDomNode.scrollWidth) { + if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { divMaxHeight += SCROLLBAR_WIDTH; } @@ -165,70 +157,70 @@ export class ResizableHoverWidget extends ResizableWidget { const widthOfEditor = editorBox.width; const leftOfEditor = editorBox.left; const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; - const leftOfContainer = this._hover.containerDomNode.offsetLeft; + const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } public override dispose(): void { this.editor.removeContentWidget(this.resizableContentWidget); - if (this._visibleData) { - this._visibleData.disposables.dispose(); + if (this.visibleData) { + this.visibleData.disposables.dispose(); } super.dispose(); } public getDomNode() { - return this._hover.containerDomNode; + return this.hoverWidget.containerDomNode; } public getContentsDomNode() { - return this._hover.contentsDomNode; + return this.hoverWidget.contentsDomNode; } public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this._visibleData) { + if (!this.visibleData) { return false; } - if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { - this._visibleData.initialMousePosX = posx; - this._visibleData.initialMousePosY = posy; + if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { + this.visibleData.initialMousePosX = posx; + this.visibleData.initialMousePosY = posy; return false; } const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); - if (typeof this._visibleData.closestMouseDistance === 'undefined') { - this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (typeof this.visibleData.closestMouseDistance === 'undefined') { + this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } - this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); + this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); return true; } private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { - if (this._visibleData) { - this._visibleData.disposables.dispose(); + if (this.visibleData) { + this.visibleData.disposables.dispose(); } - this._visibleData = visibleData; - this._hoverVisibleKey.set(!!this._visibleData); - this._hover.containerDomNode.classList.toggle('hidden', !this._visibleData); + this.visibleData = visibleData; + this.hoverVisibleKey.set(!!this.visibleData); + this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); } private _layout(): void { const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); - this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; - this._hover.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this._hover.contentsDomNode.style.maxHeight = `${height}px`; - this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; + this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); codeClasses.forEach(node => this.editor.applyFontInfo(node)); } @@ -236,7 +228,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.resizableContentWidget.position = visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; - this.resizableContentWidget.preference = [this._renderingAbove]; + this.resizableContentWidget.preference = [this.renderingAbove]; this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; this.editor.addContentWidget(this.resizableContentWidget); @@ -249,9 +241,9 @@ export class ResizableHoverWidget extends ResizableWidget { this._setVisibleData(visibleData); - this._hover.contentsDomNode.textContent = ''; - this._hover.contentsDomNode.appendChild(node); - this._hover.contentsDomNode.style.paddingBottom = ''; + this.hoverWidget.contentsDomNode.textContent = ''; + this.hoverWidget.contentsDomNode.appendChild(node); + this.hoverWidget.contentsDomNode.style.paddingBottom = ''; this._updateFont(); const containerDomNode = this.resizableContentWidget.getDomNode(); @@ -259,8 +251,8 @@ export class ResizableHoverWidget extends ResizableWidget { // If the persisted size has already been found then set a maximum height and width if (!persistedSize) { - this._hover.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); // Simply force a synchronous render on the editor @@ -270,8 +262,8 @@ export class ResizableHoverWidget extends ResizableWidget { } // When there is a persisted size then do not use a maximum height or width else { - this._hover.contentsDomNode.style.maxHeight = 'none'; - this._hover.contentsDomNode.style.maxWidth = 'none'; + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; height = persistedSize.height; } @@ -304,9 +296,9 @@ export class ResizableHoverWidget extends ResizableWidget { // Determining whether we should render above or not ideally if (this.editor.getOption(EditorOption.hover).above) { - this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; } else { - this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } // See https://github.com/microsoft/vscode/issues/140339 @@ -316,23 +308,23 @@ export class ResizableHoverWidget extends ResizableWidget { } if (visibleData.stoleFocus) { - this._hover.containerDomNode.focus(); + this.hoverWidget.containerDomNode.focus(); } visibleData.colorPicker?.layout(); - if (!this._visibleData) { + if (!this.visibleData) { return; } - const clientHeight = this._hover.containerDomNode.clientHeight; - const clientWidth = this._hover.containerDomNode.clientWidth; + const clientHeight = this.hoverWidget.containerDomNode.clientHeight; + const clientWidth = this.hoverWidget.containerDomNode.clientWidth; this.element.layout(clientHeight, clientWidth); - this.resizableContentWidget.position = this._visibleData.showAtPosition; - this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; - this.resizableContentWidget.preference = [this._renderingAbove]; - this.resizableContentWidget.positionAffinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + this.resizableContentWidget.position = this.visibleData.showAtPosition; + this.resizableContentWidget.secondaryPosition = this.visibleData.showAtSecondaryPosition; + this.resizableContentWidget.preference = [this.renderingAbove]; + this.resizableContentWidget.positionAffinity = this.visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); @@ -343,8 +335,8 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('Inside of hide of ResizableHoverWidget'); this.element.clearSashHoverState(); this.editor.removeContentWidget(this.resizableContentWidget); - if (this._visibleData) { - const stoleFocus = this._visibleData.stoleFocus; + if (this.visibleData) { + const stoleFocus = this.visibleData.stoleFocus; this._setVisibleData(null); this.editor.layoutContentWidget(this.resizableContentWidget); if (stoleFocus) { @@ -385,24 +377,24 @@ export class ResizableHoverWidget extends ResizableWidget { } this.editor.layoutContentWidget(this.resizableContentWidget); - this._hover.onContentsChanged(); + this.hoverWidget.onContentsChanged(); - const clientHeight = this._hover.containerDomNode.clientHeight; - const clientWidth = this._hover.containerDomNode.clientWidth; + const clientHeight = this.hoverWidget.containerDomNode.clientHeight; + const clientWidth = this.hoverWidget.containerDomNode.clientWidth; this.element.layout(clientHeight + 8, clientWidth + 8); // this.element.layout(clientHeight, clientWidth); - const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); console.log('hasHorizontalScrollbar: ', hasHorizontalScrollbar); // if (hasHorizontalScrollbar) { if (false) { // There is just a horizontal scrollbar - const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; - if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); @@ -415,7 +407,7 @@ export class ResizableHoverWidget extends ResizableWidget { if (reposition) { this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); - this._hover.onContentsChanged(); + this.hoverWidget.onContentsChanged(); } } } @@ -441,53 +433,53 @@ export class ResizableHoverWidget extends ResizableWidget { */ public clear(): void { - this._hover.contentsDomNode.textContent = ''; + this.hoverWidget.contentsDomNode.textContent = ''; } public focus(): void { - this._hover.containerDomNode.focus(); + this.hoverWidget.containerDomNode.focus(); } public scrollUp(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); } public scrollDown(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); } public scrollLeft(): void { - const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; - this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); } public scrollRight(): void { - const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; - this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); } public pageUp(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); } public pageDown(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); } public goToTop(): void { - this._hover.scrollbar.setScrollPosition({ scrollTop: 0 }); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); } public goToBottom(): void { - this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); } public escape(): void { From c81cd8609f76abe11ea89d5268fc33c99517a748 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 12:38:58 +0200 Subject: [PATCH 17/72] changing the id to the correct id of the resizable hover widget --- src/vs/editor/contrib/hover/browser/hover.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 445d315ba7d9a..5f6d3e6640427 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -108,7 +108,7 @@ export class ModesHoverController implements IEditorContribution { const target = mouseEvent.target; - if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID) { + if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { // ContentHoverWidget this._hoverClicked = true; // mouse down on top of content hover widget return; @@ -221,6 +221,7 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { + console.log('inside of _hideWidgets'); if ((this._isMouseDown && this._hoverClicked && this._contentWidget?.isColorPickerVisible()) || InlineSuggestionHintsContentWidget.dropDownVisible) { return; } From 3387388fef6eb7f10a7ff6f093ec3271515a02e5 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 12:48:02 +0200 Subject: [PATCH 18/72] changing the pixel positions for better rendering --- .../hover/browser/resizableHoverWidget.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 0aeb689cf2ea2..d5fed24388ebb 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -88,16 +88,17 @@ export class ResizableHoverWidget extends ResizableWidget { } public override resize(size: dom.Dimension) { + console.log('Inside of resize'); // Removing the max height and max width here - the max size is controlled by the resizable overlay this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - const width = size.width + 'px'; + const width = size.width - 7 + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; - const height = size.height + 'px'; + const height = size.height - 7 + 'px'; this.hoverWidget.containerDomNode.style.height = height; this.hoverWidget.contentsDomNode.style.height = height; @@ -106,7 +107,9 @@ export class ResizableHoverWidget extends ResizableWidget { const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + if (hasHorizontalScrollbar) { + console.log('Inside of hasHorizontalScrollbar'); // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { @@ -312,12 +315,10 @@ export class ResizableHoverWidget extends ResizableWidget { } visibleData.colorPicker?.layout(); - if (!this.visibleData) { return; } - const clientHeight = this.hoverWidget.containerDomNode.clientHeight; const clientWidth = this.hoverWidget.containerDomNode.clientWidth; this.element.layout(clientHeight, clientWidth); @@ -332,7 +333,9 @@ export class ResizableHoverWidget extends ResizableWidget { } public override hide(): void { + console.log('Inside of hide of ResizableHoverWidget'); + this.element.clearSashHoverState(); this.editor.removeContentWidget(this.resizableContentWidget); if (this.visibleData) { @@ -345,8 +348,6 @@ export class ResizableHoverWidget extends ResizableWidget { } } - // NEW - public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { console.log('Inside of onContentsChanged'); @@ -376,12 +377,15 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.height = 'auto'; } + containerDomNode.style.top = 2 + 'px'; + containerDomNode.style.left = 2 + 'px'; + this.editor.layoutContentWidget(this.resizableContentWidget); this.hoverWidget.onContentsChanged(); const clientHeight = this.hoverWidget.containerDomNode.clientHeight; const clientWidth = this.hoverWidget.containerDomNode.clientWidth; - this.element.layout(clientHeight + 8, clientWidth + 8); + this.element.layout(clientHeight + 7, clientWidth + 7); // this.element.layout(clientHeight, clientWidth); const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); From 63654814be3459e0d1565d122f3b29e0690a8f5f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 12:51:51 +0200 Subject: [PATCH 19/72] using the check on the horizontal scrollbar of height 10 in the onContentChanged function --- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index d5fed24388ebb..2073e32846047 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -392,8 +392,7 @@ export class ResizableHoverWidget extends ResizableWidget { const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); console.log('hasHorizontalScrollbar: ', hasHorizontalScrollbar); - // if (hasHorizontalScrollbar) { - if (false) { + if (hasHorizontalScrollbar) { // There is just a horizontal scrollbar const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; @@ -409,6 +408,7 @@ export class ResizableHoverWidget extends ResizableWidget { reposition = true; } if (reposition) { + this.element.layout(clientHeight + 17, clientWidth + 7); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); this.hoverWidget.onContentsChanged(); From add96e10426a6bc23fad797a25a33a6adfe8c88e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 13:03:55 +0200 Subject: [PATCH 20/72] removing 7 in the resize function --- .../hover/browser/resizableHoverWidget.ts | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 2073e32846047..f91f5929dc585 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -115,7 +115,8 @@ export class ResizableHoverWidget extends ResizableWidget { if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 7 + 'px'; + // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } this.hoverWidget.scrollbar.scanDomNode(); @@ -416,26 +417,6 @@ export class ResizableHoverWidget extends ResizableWidget { } } - // OLD FUNCTION - /* - public onContentsChanged(): void { - this.editor.layoutContentWidget(this.resizableContentWidget); - this._hover.onContentsChanged(); - - const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { - // There is just a horizontal scrollbar - const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; - if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; - this.editor.layoutContentWidget(this.resizableContentWidget); - this._hover.onContentsChanged(); - } - } - } - */ - public clear(): void { this.hoverWidget.contentsDomNode.textContent = ''; } From aadd76e0562dacd1c14557162b55c963b86678f8 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 14:41:31 +0200 Subject: [PATCH 21/72] changing the pixel values --- .../hover/browser/resizableContentWidget.ts | 46 ++++++------ .../hover/browser/resizableHoverWidget.ts | 70 ++++++++++++------- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 8fda53425a176..56e2f4d37e3be 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -19,7 +19,7 @@ export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; private readonly _disposables = new DisposableStore(); - private readonly _persistingMechanism: IPersistingMechanism; + protected readonly _persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; private resizing: boolean = false; constructor( @@ -162,7 +162,7 @@ interface IPersistingMechanism extends IDisposable { } // TODO: maybe need to make more generic, this is specific to the suggest widget -class SingleSizePersistingMechanism implements IPersistingMechanism { +export class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSize: PersistedWidgetSize | null = null; private readonly _disposables = new DisposableStore(); @@ -232,7 +232,7 @@ class SingleSizePersistingMechanism implements IPersistingMechanism { } } -class MultipleSizePersistingMechanism implements IPersistingMechanism { +export class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSizes: ResourceMap> = new ResourceMap>(); private readonly _disposables = new DisposableStore(); @@ -242,8 +242,7 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { // private _initialHeight: number = 0; // private _initialTop: number = 0; - private _resizing: boolean = false; - private _size: dom.Dimension | undefined = undefined; + // private _size: dom.Dimension | undefined = undefined; private _maxRenderingHeight: number | undefined = Infinity; private _maxRenderingWidth: number | undefined = Infinity; @@ -257,6 +256,7 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { public readonly editor: ICodeEditor ) { + console.log('Inside of constructor of the multiple size persisting mechanism'); this.element.minSize = new dom.Dimension(10, 24); this._disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; @@ -285,26 +285,30 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { } 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.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; + console.log('Inside of on did resize of the multiple size persisting mechanism'); + console.log('e : ', e); + + const height = e.dimension.height; + const 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); - 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._size = new dom.Dimension(width, height); + // this.element.layout(height, width); this.resizableWidget.resize(new dom.Dimension(width, height)); // Update the top parameters only when we decided to render above @@ -360,7 +364,9 @@ class MultipleSizePersistingMechanism implements IPersistingMechanism { const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } - this._resizing = false; + + console.log('this._persistedWidgetSizes : ', this._persistedWidgetSizes); + // this._resizing = false; } // this.editor.layoutOverlayWidget(this); diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index f91f5929dc585..ab91749d72b33 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -7,7 +7,7 @@ import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; +import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import * as dom from 'vs/base/browser/dom'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; @@ -17,7 +17,6 @@ import { PositionAffinity } from 'vs/editor/common/model'; import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; const SCROLLBAR_WIDTH = 10; - // TODO: maybe don't need the resizable widget class export class ResizableHoverWidget extends ResizableWidget { @@ -45,10 +44,11 @@ export class ResizableHoverWidget extends ResizableWidget { this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - this.hoverDisposables.add(this.element.onDidResize((e) => { - // When the resizable hover overlay changes, resize the widget - this.resize(e.dimension); - })); + // TODO: replace? + // this.hoverDisposables.add(this.element.onDidResize((e) => { + // // When the resizable hover overlay changes, resize the widget + // this.resize(e.dimension); + // })); this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); this.hoverDisposables.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { @@ -95,6 +95,8 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + console.log('size : ', size); + const width = size.width - 7 + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; @@ -230,6 +232,9 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + if (this._persistingMechanism instanceof MultipleSizePersistingMechanism) { + this._persistingMechanism.tooltipPosition = visibleData.showAtPosition; + } this.resizableContentWidget.position = visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this.renderingAbove]; @@ -239,6 +244,8 @@ export class ResizableHoverWidget extends ResizableWidget { const persistedSize = this.findPersistedSize(); + console.log('persistedSize : ', persistedSize); + if (!this.editor || !this.editor.hasModel()) { return; } @@ -320,16 +327,14 @@ export class ResizableHoverWidget extends ResizableWidget { return; } - const clientHeight = this.hoverWidget.containerDomNode.clientHeight; - const clientWidth = this.hoverWidget.containerDomNode.clientWidth; - this.element.layout(clientHeight, clientWidth); - this.resizableContentWidget.position = this.visibleData.showAtPosition; - this.resizableContentWidget.secondaryPosition = this.visibleData.showAtSecondaryPosition; - this.resizableContentWidget.preference = [this.renderingAbove]; - this.resizableContentWidget.positionAffinity = this.visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + // TODO: add maybe + // this.editor.layoutContentWidget(this.resizableContentWidget); + // this.editor.render(); + + // const clientHeight = this.hoverWidget.containerDomNode.clientHeight; + // const clientWidth = this.hoverWidget.containerDomNode.clientWidth; + // this.element.layout(clientHeight, clientWidth); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); console.log('At the end of showAt'); } @@ -349,7 +354,9 @@ export class ResizableHoverWidget extends ResizableWidget { } } - public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { + public onContentsChanged(): void { // persistedSize?: dom.Dimension | undefined + + const persistedSize = this.resizableContentWidget.findPersistedSize(); console.log('Inside of onContentsChanged'); @@ -359,9 +366,9 @@ export class ResizableHoverWidget extends ResizableWidget { // Suppose a persisted size is defined if (persistedSize) { - const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width); // - SASH_WIDTH + const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 7 - 7); // - SASH_WIDTH // const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); - const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height); // SASH_WIDTH + const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 7 - 7); // SASH_WIDTH // Already setting directly the height and width parameters containerDomNode.style.width = widthMinusSash + 'px'; @@ -386,6 +393,9 @@ export class ResizableHoverWidget extends ResizableWidget { const clientHeight = this.hoverWidget.containerDomNode.clientHeight; const clientWidth = this.hoverWidget.containerDomNode.clientWidth; + console.log('clientHeight: ', clientHeight); + console.log('clientWidth : ', clientWidth); + this.element.layout(clientHeight + 7, clientWidth + 7); // this.element.layout(clientHeight, clientWidth); @@ -404,17 +414,29 @@ export class ResizableHoverWidget extends ResizableWidget { const maxRenderingHeight = this.findMaximumRenderingHeight(); // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. if (persistedSize && maxRenderingHeight) { - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height) + 'px'; // - SASH_WIDTH - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SCROLLBAR_WIDTH) + 'px'; // - SASH_WIDTH + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9) + 'px'; // - SASH_WIDTH + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9 - SCROLLBAR_WIDTH) + 'px'; // - SASH_WIDTH reposition = true; } if (reposition) { - this.element.layout(clientHeight + 17, clientWidth + 7); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - this.hoverWidget.onContentsChanged(); + + if (persistedSize) { + console.log('Inside of the case when repositioning'); + this.element.layout(clientHeight + 17 - 6, clientWidth + 7); + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + this.hoverWidget.onContentsChanged(); + } else { + console.log('Inside of the case when repositioning'); + this.element.layout(clientHeight + 17, clientWidth + 7); + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + this.hoverWidget.onContentsChanged(); + } } } + + this.editor.layoutContentWidget(this.resizableContentWidget); } public clear(): void { From 1b7f36ce330653fdd10b9025a36156fba6fa7fcf Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 14:49:09 +0200 Subject: [PATCH 22/72] removing some redundant code --- src/vs/editor/contrib/hover/browser/hover.ts | 1 + .../editor/contrib/hover/browser/resizableContentWidget.ts | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 5f6d3e6640427..302b063828817 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -229,6 +229,7 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); if (!this._contentWidget?.widget.isResizing()) { + console.log('calling hide on content widget'); this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 56e2f4d37e3be..2a65e04f112ed 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -304,9 +304,10 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { // width = Math.min(maxWidth, width); // height = Math.min(maxHeight, height); - if (!this._maxRenderingHeight) { - return; - } + // if (!this._maxRenderingHeight) { + // console.log('returning because of the max rendering height'); + // return; + // } // this._size = new dom.Dimension(width, height); // this.element.layout(height, width); this.resizableWidget.resize(new dom.Dimension(width, height)); From f1a1c6de66753ad978749807ba586cc271dfa98f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 15:04:44 +0200 Subject: [PATCH 23/72] updating where the rendering is directly in the content widget --- src/vs/editor/browser/editorBrowser.ts | 6 +++--- src/vs/editor/contrib/hover/browser/hover.ts | 4 ++-- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index fa8ae37f759a1..75751d2db561d 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -112,15 +112,15 @@ export const enum ContentWidgetPositionPreference { /** * Place the content widget exactly at a position */ - EXACT, + EXACT = 0, /** * Place the content widget above a position */ - ABOVE, + ABOVE = 1, /** * Place the content widget below a position */ - BELOW + BELOW = 2 } /** * A position for rendering content widgets. diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 302b063828817..306fda39b0e78 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -221,7 +221,7 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { - console.log('inside of _hideWidgets'); + // console.log('inside of _hideWidgets'); if ((this._isMouseDown && this._hoverClicked && this._contentWidget?.isColorPickerVisible()) || InlineSuggestionHintsContentWidget.dropDownVisible) { return; } @@ -229,7 +229,7 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); if (!this._contentWidget?.widget.isResizing()) { - console.log('calling hide on content widget'); + // console.log('calling hide on content widget'); this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index ab91749d72b33..ca6793842fdf8 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -149,6 +149,7 @@ export class ResizableHoverWidget extends ResizableWidget { } if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { + console.log('Adding the scrollbar width when there is a horizontal scrollbar'); divMaxHeight += SCROLLBAR_WIDTH; } @@ -335,6 +336,9 @@ export class ResizableHoverWidget extends ResizableWidget { // const clientWidth = this.hoverWidget.containerDomNode.clientWidth; // this.element.layout(clientHeight, clientWidth); + this.resizableContentWidget.preference = [this.renderingAbove]; + + console.log('this.renderingAbove : ', this.renderingAbove); console.log('At the end of showAt'); } From cb0687b0c9d9283ba7fb47ce599908b2774cac2a Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 16:28:31 +0200 Subject: [PATCH 24/72] adding code for enabling the correct sashes --- src/vs/base/browser/ui/hover/hoverWidget.ts | 1 + .../editor/contrib/hover/browser/contentHover.ts | 4 ++++ src/vs/editor/contrib/hover/browser/hover.ts | 4 ++-- .../hover/browser/resizableContentWidget.ts | 8 +++++--- .../contrib/hover/browser/resizableHoverWidget.ts | 15 ++++++++++++++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/hover/hoverWidget.ts b/src/vs/base/browser/ui/hover/hoverWidget.ts index 96e99cbec4a2f..e57b1988cade7 100644 --- a/src/vs/base/browser/ui/hover/hoverWidget.ts +++ b/src/vs/base/browser/ui/hover/hoverWidget.ts @@ -37,6 +37,7 @@ export class HoverWidget extends Disposable { consumeMouseWheelIfScrollbarIsNeeded: true })); this.containerDomNode.appendChild(this.scrollbar.getDomNode()); + this.containerDomNode.style.zIndex = '50'; } public onContentsChanged(): void { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 95db16377f5c6..b1bb384c818f5 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -87,6 +87,7 @@ export class ContentHoverController extends Disposable { // While the hover overlay is resizing, the hover is showing if (this._widget.isResizing()) { + console.log('early return because is resizing'); return true; } @@ -153,6 +154,7 @@ export class ContentHoverController extends Disposable { } if (!anchor) { + console.log('iniside of no anchor'); this._setCurrentResult(null); return false; } @@ -164,6 +166,7 @@ export class ContentHoverController extends Disposable { if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { // The new anchor is not compatible with the previous anchor + console.log('inside of cn not adopt visible hover'); this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); return true; @@ -207,6 +210,7 @@ export class ContentHoverController extends Disposable { } public hide(): void { + console.log('inside of hide of content hover controller'); this._computer.anchor = null; this._hoverOperation.cancel(); this._setCurrentResult(null); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 306fda39b0e78..302b063828817 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -221,7 +221,7 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { - // console.log('inside of _hideWidgets'); + console.log('inside of _hideWidgets'); if ((this._isMouseDown && this._hoverClicked && this._contentWidget?.isColorPickerVisible()) || InlineSuggestionHintsContentWidget.dropDownVisible) { return; } @@ -229,7 +229,7 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); if (!this._contentWidget?.widget.isResizing()) { - // console.log('calling hide on content widget'); + console.log('calling hide on content widget'); this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 2a65e04f112ed..c1fc30477fb92 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -43,8 +43,10 @@ export abstract class ResizableWidget implements IDisposable { this._disposables.add(this.element.onDidWillResize(() => { this.resizing = true; })); - this._disposables.add(this.element.onDidResize(() => { - this.resizing = false; + this._disposables.add(this.element.onDidResize((e) => { + if (e.done) { + this.resizing = false; + } })); } @@ -102,7 +104,7 @@ export abstract class ResizableContentWidget implements IContentWidget { 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.zIndex = '100'; this.resizableWidget.element.domNode.style.position = 'fixed'; // this.resizableWidget.element.domNode.style.display = 'block'; return this.resizableWidget.element.domNode; diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index ca6793842fdf8..c4729d6eb89d3 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -17,7 +17,10 @@ import { PositionAffinity } from 'vs/editor/common/model'; import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; const SCROLLBAR_WIDTH = 10; + // TODO: maybe don't need the resizable widget class +// TODO: How to increase the z-index so that appears above the tabs? Somehow does not work + export class ResizableHoverWidget extends ResizableWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; @@ -124,6 +127,8 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); + + console.log('this.resizableContentWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); } public override findMaximumRenderingHeight(): number | undefined { @@ -240,7 +245,8 @@ export class ResizableHoverWidget extends ResizableWidget { this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this.renderingAbove]; this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - + this.resizableContentWidget.getDomNode().style.position = 'fixed'; + this.resizableContentWidget.getDomNode().style.zIndex = '100'; this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); @@ -313,6 +319,12 @@ export class ResizableHoverWidget extends ResizableWidget { this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + this.element.enableSashes(true, true, false, false); + } else { + this.element.enableSashes(false, true, true, false); + } + // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!persistedSize) { @@ -440,6 +452,7 @@ export class ResizableHoverWidget extends ResizableWidget { } } + console.log('this.resizableContentWidget : ', this.resizableContentWidget); this.editor.layoutContentWidget(this.resizableContentWidget); } From 72a9e3b70711a38b2f596374c084532ca9eb30fd Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 16:35:27 +0200 Subject: [PATCH 25/72] cleaning the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 8 +------- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index b1bb384c818f5..7ecc5bf072883 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -31,7 +31,7 @@ const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - private readonly _widget; + private readonly _widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; @@ -44,7 +44,6 @@ export class ContentHoverController extends Disposable { ) { super(); - this._widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; for (const participant of HoverParticipantRegistry.getAll()) { @@ -87,10 +86,8 @@ export class ContentHoverController extends Disposable { // While the hover overlay is resizing, the hover is showing if (this._widget.isResizing()) { - console.log('early return because is resizing'); return true; } - const anchorCandidates: HoverAnchor[] = []; for (const participant of this._participants) { @@ -154,7 +151,6 @@ export class ContentHoverController extends Disposable { } if (!anchor) { - console.log('iniside of no anchor'); this._setCurrentResult(null); return false; } @@ -166,7 +162,6 @@ export class ContentHoverController extends Disposable { if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { // The new anchor is not compatible with the previous anchor - console.log('inside of cn not adopt visible hover'); this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); return true; @@ -210,7 +205,6 @@ export class ContentHoverController extends Disposable { } public hide(): void { - console.log('inside of hide of content hover controller'); this._computer.anchor = null; this._hoverOperation.cancel(); this._setCurrentResult(null); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 302b063828817..306abe39d4a9c 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -17,7 +17,6 @@ import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/go import { HoverStartMode, HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { ContentHoverWidget, ContentHoverController } from 'vs/editor/contrib/hover/browser/contentHover'; import { MarginHoverWidget } from 'vs/editor/contrib/hover/browser/marginHover'; -import * as nls from 'vs/nls'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -31,6 +30,7 @@ import 'vs/css!./hover'; import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineSuggestionHintsWidget'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; +import * as nls from 'vs/nls'; export class ModesHoverController implements IEditorContribution { From 5b5bd722a7710aef703302db46a2765c07f8a67d Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 3 Apr 2023 18:59:45 +0200 Subject: [PATCH 26/72] changing the pixel change --- src/vs/base/browser/ui/resizable/resizable.ts | 16 ++++ src/vs/base/browser/ui/sash/sash.ts | 79 ++++++++++--------- .../hover/browser/resizableHoverWidget.ts | 45 ++++++++++- 3 files changed, 100 insertions(+), 40 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index 95dfb06b8d007..9bd5f4ff54219 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -187,4 +187,20 @@ export class ResizableHTMLElement { get preferredSize() { return this._preferredSize; } + + get northSash() { + return this._northSash; + } + + get eastSash() { + return this._eastSash; + } + + get westSash() { + return this._westSash; + } + + get southSash() { + return this._southSash; + } } diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index b20c218516917..4ef97c14f2ad2 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -247,7 +247,7 @@ const PointerEventsDisabledCssClass = 'pointer-events-disabled'; */ export class Sash extends Disposable { - private el: HTMLElement; + private _el: HTMLElement; private layoutProvider: ISashLayoutProvider; private orientation: Orientation; private size: number; @@ -270,6 +270,7 @@ export class Sash extends Disposable { private _orthogonalEndDragHandle: HTMLElement | undefined; get state(): SashState { return this._state; } + get el(): HTMLElement { return this._el; } get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; } get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; } @@ -282,9 +283,9 @@ export class Sash extends Disposable { return; } - this.el.classList.toggle('disabled', state === SashState.Disabled); - this.el.classList.toggle('minimum', state === SashState.AtMinimum); - this.el.classList.toggle('maximum', state === SashState.AtMaximum); + this._el.classList.toggle('disabled', state === SashState.Disabled); + this._el.classList.toggle('minimum', state === SashState.AtMinimum); + this._el.classList.toggle('maximum', state === SashState.AtMaximum); this._state = state; this.onDidEnablementChange.fire(state); @@ -336,7 +337,7 @@ export class Sash extends Disposable { this.orthogonalStartDragHandleDisposables.clear(); if (state !== SashState.Disabled) { - this._orthogonalStartDragHandle = append(this.el, $('.orthogonal-drag-handle.start')); + this._orthogonalStartDragHandle = append(this._el, $('.orthogonal-drag-handle.start')); this.orthogonalStartDragHandleDisposables.add(toDisposable(() => this._orthogonalStartDragHandle!.remove())); this.orthogonalStartDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalStartDragHandleDisposables); @@ -370,7 +371,7 @@ export class Sash extends Disposable { this.orthogonalEndDragHandleDisposables.clear(); if (state !== SashState.Disabled) { - this._orthogonalEndDragHandle = append(this.el, $('.orthogonal-drag-handle.end')); + this._orthogonalEndDragHandle = append(this._el, $('.orthogonal-drag-handle.end')); this.orthogonalEndDragHandleDisposables.add(toDisposable(() => this._orthogonalEndDragHandle!.remove())); this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalEndDragHandleDisposables); @@ -406,30 +407,30 @@ export class Sash extends Disposable { constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) { super(); - this.el = append(container, $('.monaco-sash')); + this._el = append(container, $('.monaco-sash')); if (options.orthogonalEdge) { - this.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`); + this._el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`); } if (isMacintosh) { - this.el.classList.add('mac'); + this._el.classList.add('mac'); } - const onMouseDown = this._register(new DomEmitter(this.el, 'mousedown')).event; + const onMouseDown = this._register(new DomEmitter(this._el, 'mousedown')).event; this._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory()), this)); - const onMouseDoubleClick = this._register(new DomEmitter(this.el, 'dblclick')).event; + const onMouseDoubleClick = this._register(new DomEmitter(this._el, 'dblclick')).event; this._register(onMouseDoubleClick(this.onPointerDoublePress, this)); - const onMouseEnter = this._register(new DomEmitter(this.el, 'mouseenter')).event; + const onMouseEnter = this._register(new DomEmitter(this._el, 'mouseenter')).event; this._register(onMouseEnter(() => Sash.onMouseEnter(this))); - const onMouseLeave = this._register(new DomEmitter(this.el, 'mouseleave')).event; + const onMouseLeave = this._register(new DomEmitter(this._el, 'mouseleave')).event; this._register(onMouseLeave(() => Sash.onMouseLeave(this))); - this._register(Gesture.addTarget(this.el)); + this._register(Gesture.addTarget(this._el)); - const onTouchStart = this._register(new DomEmitter(this.el, EventType.Start)).event; - this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this.el)), this)); - const onTap = this._register(new DomEmitter(this.el, EventType.Tap)).event; + const onTouchStart = this._register(new DomEmitter(this._el, EventType.Start)).event; + this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this._el)), this)); + const onTap = this._register(new DomEmitter(this._el, EventType.Tap)).event; let doubleTapTimeout: any = undefined; this._register(onTap(event => { @@ -448,9 +449,9 @@ export class Sash extends Disposable { this.size = options.size; if (options.orientation === Orientation.VERTICAL) { - this.el.style.width = `${this.size}px`; + this._el.style.width = `${this.size}px`; } else { - this.el.style.height = `${this.size}px`; + this._el.style.height = `${this.size}px`; } } else { this.size = globalSize; @@ -470,14 +471,14 @@ export class Sash extends Disposable { this.orientation = options.orientation || Orientation.VERTICAL; if (this.orientation === Orientation.HORIZONTAL) { - this.el.classList.add('horizontal'); - this.el.classList.remove('vertical'); + this._el.classList.add('horizontal'); + this._el.classList.remove('vertical'); } else { - this.el.classList.remove('horizontal'); - this.el.classList.add('vertical'); + this._el.classList.remove('horizontal'); + this._el.classList.add('vertical'); } - this.el.classList.toggle('debug', DEBUG); + this._el.classList.toggle('debug', DEBUG); this.layout(); } @@ -516,11 +517,11 @@ export class Sash extends Disposable { const altKey = event.altKey; const startEvent: ISashEvent = { startX, currentX: startX, startY, currentY: startY, altKey }; - this.el.classList.add('active'); + this._el.classList.add('active'); this._onDidStart.fire(startEvent); // fix https://github.com/microsoft/vscode/issues/21675 - const style = createStyleSheet(this.el); + const style = createStyleSheet(this._el); const updateStyle = () => { let cursor = ''; @@ -565,9 +566,9 @@ export class Sash extends Disposable { const onPointerUp = (e: PointerEvent) => { EventHelper.stop(e, false); - this.el.removeChild(style); + this._el.removeChild(style); - this.el.classList.remove('active'); + this._el.classList.remove('active'); this._onDidEnd.fire(); disposables.dispose(); @@ -597,11 +598,11 @@ export class Sash extends Disposable { } private static onMouseEnter(sash: Sash, fromLinkedSash: boolean = false): void { - if (sash.el.classList.contains('active')) { + if (sash._el.classList.contains('active')) { sash.hoverDelayer.cancel(); - sash.el.classList.add('hover'); + sash._el.classList.add('hover'); } else { - sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { }); + sash.hoverDelayer.trigger(() => sash._el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { }); } if (!fromLinkedSash && sash.linkedSash) { @@ -611,7 +612,7 @@ export class Sash extends Disposable { private static onMouseLeave(sash: Sash, fromLinkedSash: boolean = false): void { sash.hoverDelayer.cancel(); - sash.el.classList.remove('hover'); + sash._el.classList.remove('hover'); if (!fromLinkedSash && sash.linkedSash) { Sash.onMouseLeave(sash.linkedSash, true); @@ -634,25 +635,25 @@ export class Sash extends Disposable { layout(): void { if (this.orientation === Orientation.VERTICAL) { const verticalProvider = (this.layoutProvider); - this.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px'; + this._el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px'; if (verticalProvider.getVerticalSashTop) { - this.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px'; + this._el.style.top = verticalProvider.getVerticalSashTop(this) + 'px'; } if (verticalProvider.getVerticalSashHeight) { - this.el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px'; + this._el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px'; } } else { const horizontalProvider = (this.layoutProvider); - this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px'; + this._el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px'; if (horizontalProvider.getHorizontalSashLeft) { - this.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px'; + this._el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px'; } if (horizontalProvider.getHorizontalSashWidth) { - this.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px'; + this._el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px'; } } } @@ -673,6 +674,6 @@ export class Sash extends Disposable { override dispose(): void { super.dispose(); - this.el.remove(); + this._el.remove(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index c4729d6eb89d3..a5c6f092d7b42 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -124,6 +124,17 @@ export class ResizableHoverWidget extends ResizableWidget { // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } + const sashWidth = size.width - 5 + 'px'; + const sashHeight = size.height - 5 + 'px'; + this.element.northSash.el.style.width = sashWidth; + this.element.southSash.el.style.width = sashWidth; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; + this.element.eastSash.el.style.height = sashHeight; + this.element.westSash.el.style.height = sashHeight; + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; + this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); @@ -435,9 +446,10 @@ export class ResizableHoverWidget extends ResizableWidget { reposition = true; } if (reposition) { + console.log('Inside of the case when repositioning'); if (persistedSize) { - console.log('Inside of the case when repositioning'); + console.log('when using a persisted size'); this.element.layout(clientHeight + 17 - 6, clientWidth + 7); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); @@ -453,6 +465,37 @@ export class ResizableHoverWidget extends ResizableWidget { } console.log('this.resizableContentWidget : ', this.resizableContentWidget); + + // --- + + console.log('Before changing the sash size'); + + const size = this.element.size; + let height = size.height; + const width = size.width; + this.element.northSash.el.style.width = width - 4 + 'px'; + this.element.southSash.el.style.width = width - 4 + 'px'; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; + + if (hasHorizontalScrollbar) { + height = clientHeight + 12; + } else { + height = clientHeight + 2; + } + + if (!persistedSize) { + this.element.eastSash.el.style.height = height + 'px'; + this.element.westSash.el.style.height = height + 'px'; + } else { + this.element.eastSash.el.style.height = height - 5 + 'px'; + this.element.westSash.el.style.height = height - 5 + 'px'; + } + + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; + // --- + this.editor.layoutContentWidget(this.resizableContentWidget); } From 8a07e1dbc3c1ea8a630b13815f8d433451e3c796 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 13:09:19 +0200 Subject: [PATCH 27/72] cleaning the code --- src/vs/editor/browser/editorBrowser.ts | 6 +- .../contrib/hover/browser/contentHover.ts | 277 +---------------- src/vs/editor/contrib/hover/browser/hover.ts | 19 +- .../hover/browser/resizableContentWidget.ts | 279 ++++++++---------- .../hover/browser/resizableHoverWidget.ts | 151 ++++------ 5 files changed, 203 insertions(+), 529 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 75751d2db561d..fa8ae37f759a1 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -112,15 +112,15 @@ export const enum ContentWidgetPositionPreference { /** * Place the content widget exactly at a position */ - EXACT = 0, + EXACT, /** * Place the content widget above a position */ - ABOVE = 1, + ABOVE, /** * Place the content widget below a position */ - BELOW = 2 + BELOW } /** * A position for rendering content widgets. diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 7ecc5bf072883..1d5b36c3dd345 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -4,26 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { HoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; +import { HoverAction } from 'vs/base/browser/ui/hover/hoverWidget'; import { coalesce } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IModelDecoration, PositionAffinity } from 'vs/editor/common/model'; +import { IModelDecoration } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { TokenizationRegistry } from 'vs/editor/common/languages'; import { HoverOperation, HoverStartMode, HoverStartSource, IHoverComputer } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { HoverAnchor, HoverAnchorType, HoverParticipantRegistry, HoverRangeAnchor, IEditorHoverColorPickerWidget, IEditorHoverAction, IEditorHoverParticipant, IEditorHoverRenderContext, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest'; import { AsyncIterableObject } from 'vs/base/common/async'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; const $ = dom.$; @@ -151,6 +148,9 @@ export class ContentHoverController extends Disposable { } if (!anchor) { + + console.log('no anchor'); + this._setCurrentResult(null); return false; } @@ -161,6 +161,9 @@ export class ContentHoverController extends Disposable { } if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { + + console.log('can not adopt visible hover'); + // The new anchor is not compatible with the previous anchor this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); @@ -447,258 +450,6 @@ class ContentHoverVisibleData { ) { } } -export class ContentHoverWidget extends Disposable implements IContentWidget { - - static readonly ID = 'editor.contrib.contentHoverWidget'; - - public readonly allowEditorOverflow = true; - - private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); - private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); - private readonly _hover: HoverWidget = this._register(new HoverWidget()); - private readonly _focusTracker = this._register(dom.trackFocus(this.getDomNode())); - private readonly _horizontalScrollingBy: number = 30; - private _visibleData: ContentHoverVisibleData | null = null; - - /** - * Returns `null` if the hover is not visible. - */ - public get position(): Position | null { - return this._visibleData?.showAtPosition ?? null; - } - - public get isColorPickerVisible(): boolean { - return Boolean(this._visibleData?.colorPicker); - } - - public get isVisibleFromKeyboard(): boolean { - return (this._visibleData?.source === HoverStartSource.Keyboard); - } - - public get isVisible(): boolean { - return this._hoverVisibleKey.get() ?? false; - } - - constructor( - private readonly _editor: ICodeEditor, - @IContextKeyService private readonly _contextKeyService: IContextKeyService, - ) { - super(); - - this._register(this._editor.onDidLayoutChange(() => this._layout())); - this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { - if (e.hasChanged(EditorOption.fontInfo)) { - this._updateFont(); - } - })); - - this._setVisibleData(null); - this._layout(); - this._editor.addContentWidget(this); - - this._register(this._focusTracker.onDidFocus(() => { - this._hoverFocusedKey.set(true); - })); - this._register(this._focusTracker.onDidBlur(() => { - this._hoverFocusedKey.set(false); - })); - } - - public override dispose(): void { - this._editor.removeContentWidget(this); - if (this._visibleData) { - this._visibleData.disposables.dispose(); - } - super.dispose(); - } - - public getId(): string { - return ContentHoverWidget.ID; - } - - public getDomNode(): HTMLElement { - return this._hover.containerDomNode; - } - - public getPosition(): IContentWidgetPosition | null { - if (!this._visibleData) { - return null; - } - let preferAbove = this._visibleData.preferAbove; - if (!preferAbove && this._contextKeyService.getContextKeyValue(SuggestContext.Visible.key)) { - // Prefer rendering above if the suggest widget is visible - preferAbove = true; - } - - // :before content can align left of the text content - const affinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - - return { - position: this._visibleData.showAtPosition, - secondaryPosition: this._visibleData.showAtSecondaryPosition, - preference: ( - preferAbove - ? [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW] - : [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE] - ), - positionAffinity: affinity - }; - } - - public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this._visibleData) { - return false; - } - if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { - this._visibleData.initialMousePosX = posx; - this._visibleData.initialMousePosY = posy; - return false; - } - - const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); - if (typeof this._visibleData.closestMouseDistance === 'undefined') { - this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - } - const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { - // The mouse is getting farther away - return false; - } - this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); - return true; - } - - private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { - if (this._visibleData) { - this._visibleData.disposables.dispose(); - } - this._visibleData = visibleData; - this._hoverVisibleKey.set(!!this._visibleData); - this._hover.containerDomNode.classList.toggle('hidden', !this._visibleData); - } - - private _layout(): void { - const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); - - this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; - this._hover.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this._hover.contentsDomNode.style.maxHeight = `${height}px`; - this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; - } - - private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); - codeClasses.forEach(node => this._editor.applyFontInfo(node)); - } - - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - this._setVisibleData(visibleData); - - this._hover.contentsDomNode.textContent = ''; - this._hover.contentsDomNode.appendChild(node); - this._hover.contentsDomNode.style.paddingBottom = ''; - this._updateFont(); - - this.onContentsChanged(); - - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); - - // See https://github.com/microsoft/vscode/issues/140339 - // TODO: Doing a second layout of the hover after force rendering the editor - this.onContentsChanged(); - - if (visibleData.stoleFocus) { - this._hover.containerDomNode.focus(); - } - visibleData.colorPicker?.layout(); - } - - public hide(): void { - if (this._visibleData) { - const stoleFocus = this._visibleData.stoleFocus; - this._setVisibleData(null); - this._editor.layoutContentWidget(this); - if (stoleFocus) { - this._editor.focus(); - } - } - } - - public onContentsChanged(): void { - this._editor.layoutContentWidget(this); - this._hover.onContentsChanged(); - - const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { - // There is just a horizontal scrollbar - const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; - if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; - this._editor.layoutContentWidget(this); - this._hover.onContentsChanged(); - } - } - } - - public clear(): void { - this._hover.contentsDomNode.textContent = ''; - } - - public focus(): void { - this._hover.containerDomNode.focus(); - } - - public scrollUp(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this._editor.getOption(EditorOption.fontInfo); - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); - } - - public scrollDown(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this._editor.getOption(EditorOption.fontInfo); - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); - } - - public scrollLeft(): void { - const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; - this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); - } - - public scrollRight(): void { - const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; - this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); - } - - public pageUp(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); - } - - public pageDown(): void { - const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; - this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); - } - - public goToTop(): void { - this._hover.scrollbar.setScrollPosition({ scrollTop: 0 }); - } - - public goToBottom(): void { - this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); - } - - public escape(): void { - this._editor.focus(); - } -} - class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { public readonly hoverElement: HTMLElement; @@ -824,11 +575,3 @@ class ContentHoverComputer implements IHoverComputer { return coalesce(result); } } - -function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { - const x = (left + width / 2); // x center of rectangle - const y = (top + height / 2); // y center of rectangle - const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); - const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); - return Math.sqrt(dx * dx + dy * dy); -} diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 306abe39d4a9c..90fce0e8d75bb 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -15,7 +15,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition'; import { HoverStartMode, HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { ContentHoverWidget, ContentHoverController } from 'vs/editor/contrib/hover/browser/contentHover'; +import { ContentHoverController } from 'vs/editor/contrib/hover/browser/contentHover'; import { MarginHoverWidget } from 'vs/editor/contrib/hover/browser/marginHover'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -26,12 +26,11 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { HoverParticipantRegistry } from 'vs/editor/contrib/hover/browser/hoverTypes'; import { MarkdownHoverParticipant } from 'vs/editor/contrib/hover/browser/markdownHoverParticipant'; import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/browser/markerHoverParticipant'; -import 'vs/css!./hover'; import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineSuggestionHintsWidget'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; +import { ResizableContentHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; import * as nls from 'vs/nls'; - +import 'vs/css!./hover'; export class ModesHoverController implements IEditorContribution { public static readonly ID = 'editor.contrib.hover'; @@ -108,7 +107,7 @@ export class ModesHoverController implements IEditorContribution { const target = mouseEvent.target; - if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { // ContentHoverWidget + if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { this._hoverClicked = true; // mouse down on top of content hover widget return; @@ -146,7 +145,7 @@ export class ModesHoverController implements IEditorContribution { return; } - if (this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID) { + if (this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { // mouse moved on top of content hover widget return; } @@ -157,7 +156,7 @@ export class ModesHoverController implements IEditorContribution { } if ( - !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID + !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID && this._contentWidget?.isColorPickerVisible() ) { // though the hover is not sticky, the color picker needs to. @@ -169,8 +168,8 @@ export class ModesHoverController implements IEditorContribution { return; } - if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { - // mouse down on top of the overlay hover widget + if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { + // mouse down on top of the content hover widget return; } @@ -221,7 +220,6 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { - console.log('inside of _hideWidgets'); if ((this._isMouseDown && this._hoverClicked && this._contentWidget?.isColorPickerVisible()) || InlineSuggestionHintsContentWidget.dropDownVisible) { return; } @@ -229,7 +227,6 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); if (!this._contentWidget?.widget.isResizing()) { - console.log('calling hide on content widget'); this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index c1fc30477fb92..3d0318806342f 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -3,63 +3,84 @@ * 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 { 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'; +import * as dom from 'vs/base/browser/dom'; + +export interface IResizableWidget extends IDisposable { + + isResizing(): boolean; + + resize(dimension: dom.Dimension): void; + + hide(): void; + + findMaximumRenderingHeight(): number | undefined; + + findMaximumRenderingWidth(): number | undefined; + + findPersistedSize(): dom.Dimension | undefined; -export abstract class ResizableWidget implements IDisposable { + beforeOnDidWillResize(): void; - readonly element: ResizableHTMLElement; - private readonly _disposables = new DisposableStore(); - protected readonly _persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; + afterOnDidResize(): void; + + dispose(): void; +} + +export abstract class ResizableWidget implements IResizableWidget { + + public readonly element: ResizableHTMLElement; + protected readonly persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; + private readonly disposables = new DisposableStore(); private resizing: boolean = false; constructor( - private readonly _editor: ICodeEditor, - private readonly _persistingOptions: IPersistingOptions, + 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'); + this.element = this.disposables.add(new ResizableHTMLElement()); + this.element.minSize = new dom.Dimension(10, 24); - 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); + if (this.persistingOptions instanceof SingleSizePersistingOptions) { + this.persistingMechanism = new SingleSizePersistingMechanism(this, this.editor, this.persistingOptions); + } else if (this.persistingOptions instanceof MultipleSizePersistingOptions) { + this.persistingMechanism = new MultipleSizePersistingMechanism(this, this.editor); } else { throw new Error('Please specify a valid persisting mechanism'); } - this._disposables.add(this.element.onDidWillResize(() => { + this.disposables.add(this.element.onDidWillResize(() => { this.resizing = true; })); - this._disposables.add(this.element.onDidResize((e) => { + this.disposables.add(this.element.onDidResize((e) => { if (e.done) { this.resizing = false; } })); } - public isResizing() { + isResizing() { return this.resizing; } dispose(): void { - this._disposables.dispose(); - this.element.dispose(); + this.disposables.dispose(); } - resize(dimension: dom.Dimension): void { } + resize(dimension: dom.Dimension): void { + this.element.layout(dimension.height, dimension.width); + } hide(): void { this.resizing = false; @@ -75,57 +96,80 @@ export abstract class ResizableWidget implements IDisposable { } findPersistedSize(): dom.Dimension | undefined { - return this._persistingMechanism.findSize(); + return this.persistingMechanism.findSize(); + } + + beforeOnDidWillResize() { + return; } + + afterOnDidResize() { + return; + } +} + +export interface IResizableContentWidget { + + findPersistedSize(): dom.Dimension | undefined; + + getId(): string; + + getDomNode(): HTMLElement; + + getPosition(): IContentWidgetPosition | null; + + hide(): void; } 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'); + constructor( + private readonly resizableWidget: ResizableWidget, + private readonly editor: ICodeEditor + ) { + console.log('Inside of ResizableContentWidget constructor'); } + abstract getId(): string; + 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 = '100'; - 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 { + console.log('Inside of hide of the ResizableContentWidget'); - this.editor.layoutContentWidget(this); + + this.editor.removeContentWidget(this); } set position(position: IPosition | null) { @@ -163,109 +207,79 @@ interface IPersistingMechanism extends IDisposable { findSize(): dom.Dimension | undefined; } -// TODO: maybe need to make more generic, this is specific to the suggest widget export class SingleSizePersistingMechanism implements IPersistingMechanism { - private readonly _persistedWidgetSize: PersistedWidgetSize | null = null; - private readonly _disposables = new DisposableStore(); + 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, - ) { } - } + this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); 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.resizableWidget.element.onDidWillResize(() => { + this.resizableWidget.beforeOnDidWillResize(); + state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.element.size); })); - this._disposables.add(this.element.onDidResize(e => { - + this.disposables.add(this.resizableWidget.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; + let { width, height } = this.resizableWidget.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)); + this.persistedWidgetSize!.store(new dom.Dimension(width, height)); } - - // TODO: add back, reset working state - // this._contentWidget.unlockPreference(); + this.resizableWidget.afterOnDidResize(); state = undefined; })); } findSize(): dom.Dimension | undefined { - return undefined; + return this.persistedWidgetSize?.restore(); } dispose(): void { - this._disposables.dispose(); + this.disposables.dispose(); } } export class MultipleSizePersistingMechanism implements IPersistingMechanism { - private readonly _persistedWidgetSizes: ResourceMap> = new ResourceMap>(); - 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 _size: dom.Dimension | undefined = undefined; - private _maxRenderingHeight: number | undefined = Infinity; - private _maxRenderingWidth: number | undefined = Infinity; - - private readonly _onDidResize = new Emitter(); - readonly onDidResize: Event = this._onDidResize.event; - // private _renderingAbove: ContentWidgetPositionPreference | undefined = undefined; + private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); + private readonly disposables = new DisposableStore(); + private _position: IPosition | null = null; constructor( private readonly resizableWidget: ResizableWidget, - private readonly element: ResizableHTMLElement, public readonly editor: ICodeEditor ) { console.log('Inside of constructor of the multiple size persisting mechanism'); - this.element.minSize = new dom.Dimension(10, 24); - this._disposables.add(this.editor.onDidChangeModelContent((e) => { + + this.disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; - if (!uri || !this._persistedWidgetSizes.has(uri)) { + if (!uri || !this.persistedWidgetSizes.has(uri)) { return; } - const persistedSizesForUri = this._persistedWidgetSizes.get(uri)!; + const persistedSizesForUri = this.persistedWidgetSizes.get(uri)!; const updatedPersistedSizesForUri = new Map(); for (const change of e.changes) { const changeOffset = change.rangeOffset; @@ -285,14 +299,10 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } } } - this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); + 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 => { + + this.disposables.add(this.resizableWidget.element.onDidResize(e => { console.log('Inside of on did resize of the multiple size persisting mechanism'); console.log('e : ', e); @@ -300,103 +310,64 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { const height = e.dimension.height; const 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) { - // console.log('returning because of the max rendering height'); - // return; - // } - // this._size = new dom.Dimension(width, height); - // this.element.layout(height, width); 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) { + const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); + const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); + + if (!maxRenderingWidth || !maxRenderingHeight) { return; } - this.element.maxSize = new dom.Dimension(this._maxRenderingWidth, this._maxRenderingHeight); + this.resizableWidget.element.maxSize = new dom.Dimension(maxRenderingWidth, 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) { + if (!uri || !this._position) { return; } const persistedSize = new dom.Dimension(width, height); - const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); + const wordPosition = this.editor.getModel().getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); + const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.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)) { + if (!this.persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); - this._persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); + this.persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); } else { - const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; + const persistedWidgetSizesForUri = this.persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } - - console.log('this._persistedWidgetSizes : ', this._persistedWidgetSizes); - // this._resizing = false; } - - // this.editor.layoutOverlayWidget(this); - // this.editor.render(); })); - } - set tooltipPosition(position: IPosition) { - this._tooltipPosition = position; + set position(position: IPosition) { + this._position = position; } findSize(): dom.Dimension | undefined { console.log('Inside of findSize of the MultiplePersistingMechanisms'); - if (!this._tooltipPosition || !this.editor.hasModel()) { + if (!this._position || !this.editor.hasModel()) { return; } - const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); + const wordPosition = this.editor.getModel().getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); + const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; const uri = this.editor.getModel().uri; - const persistedSizesForUri = this._persistedWidgetSizes.get(uri); + const persistedSizesForUri = this.persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; } @@ -404,7 +375,7 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } dispose(): void { - this._disposables.dispose(); + this.disposables.dispose(); } } @@ -412,8 +383,7 @@ class PersistedWidgetSize { constructor( private readonly _key: string, - private readonly _service: IStorageService, - editor: ICodeEditor + private readonly _service: IStorageService ) { } restore(): dom.Dimension | undefined { @@ -437,3 +407,12 @@ class PersistedWidgetSize { this._service.remove(this._key, StorageScope.PROFILE); } } + +class ResizeState { + constructor( + readonly persistedSize: dom.Dimension | undefined, + readonly currentSize: dom.Dimension, + public persistHeight = false, + public persistWidth = false, + ) { } +} diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index a5c6f092d7b42..d196c14e0e5e9 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -15,63 +14,51 @@ import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { PositionAffinity } from 'vs/editor/common/model'; import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; +import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; const SCROLLBAR_WIDTH = 10; -// TODO: maybe don't need the resizable widget class // TODO: How to increase the z-index so that appears above the tabs? Somehow does not work export class ResizableHoverWidget extends ResizableWidget { - public static ID = 'editor.contrib.resizableContentHoverWidget'; - private hoverDisposables = new DisposableStore(); + private disposableStore = new DisposableStore(); private resizableContentWidget: ResizableContentHoverWidget; - public readonly hoverWidget: HoverWidget = this.hoverDisposables.add(new HoverWidget()); + private visibleData: ContentHoverVisibleData | null = null; + private renderingAbove: ContentWidgetPositionPreference; + public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); public readonly allowEditorOverflow = true; - private readonly editor: ICodeEditor; + private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); - private readonly focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); + private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.getDomNode())); private readonly horizontalScrollingBy: number = 30; - private visibleData: ContentHoverVisibleData | null = null; - private renderingAbove: ContentWidgetPositionPreference; constructor( editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { super(editor, new MultipleSizePersistingOptions()); + dom.append(this.element.domNode, this.hoverWidget.containerDomNode); - this.editor = editor; this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - // TODO: replace? - // this.hoverDisposables.add(this.element.onDidResize((e) => { - // // When the resizable hover overlay changes, resize the widget - // this.resize(e.dimension); - // })); - - this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); - this.hoverDisposables.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); + this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); - this._setVisibleData(null); - this._layout(); - - this.hoverDisposables.add(this.focusTracker.onDidFocus(() => { + this.disposableStore.add(this.focusTracker.onDidFocus(() => { this.hoverFocusedKey.set(true); })); - this.hoverDisposables.add(this.focusTracker.onDidBlur(() => { + this.disposableStore.add(this.focusTracker.onDidBlur(() => { this.hoverFocusedKey.set(false); })); - - // containerDomNode added to the element dom node - // the element.domNode is returned by the getDomNode() of the ContentWidget - dom.append(this.element.domNode, this.hoverWidget.containerDomNode); + this._setVisibleData(null); + this._layout(); } public get position(): Position | null { @@ -93,13 +80,12 @@ export class ResizableHoverWidget extends ResizableWidget { public override resize(size: dom.Dimension) { console.log('Inside of resize'); + console.log('size : ', size); - // Removing the max height and max width here - the max size is controlled by the resizable overlay this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - console.log('size : ', size); - + // TODO: Change the pixel sizes const width = size.width - 7 + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; @@ -107,39 +93,31 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.containerDomNode.style.height = height; this.hoverWidget.contentsDomNode.style.height = height; - // const width = size.width - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; - // const height = size.height - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; + const sashWidth = size.width - 5 + 'px'; + const sashHeight = size.height - 5 + 'px'; + this.element.northSash.el.style.width = sashWidth; + this.element.southSash.el.style.width = sashWidth; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; + this.element.eastSash.el.style.height = sashHeight; + this.element.westSash.el.style.height = sashHeight; + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { - console.log('Inside of hasHorizontalScrollbar'); // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 7 + 'px'; - // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } - const sashWidth = size.width - 5 + 'px'; - const sashHeight = size.height - 5 + 'px'; - this.element.northSash.el.style.width = sashWidth; - this.element.southSash.el.style.width = sashWidth; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - this.element.eastSash.el.style.height = sashHeight; - this.element.westSash.el.style.height = sashHeight; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; - this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - - console.log('this.resizableContentWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); } public override findMaximumRenderingHeight(): number | undefined { @@ -165,7 +143,9 @@ export class ResizableHoverWidget extends ResizableWidget { } if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { + console.log('Adding the scrollbar width when there is a horizontal scrollbar'); + divMaxHeight += SCROLLBAR_WIDTH; } @@ -249,21 +229,19 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - if (this._persistingMechanism instanceof MultipleSizePersistingMechanism) { - this._persistingMechanism.tooltipPosition = visibleData.showAtPosition; + if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { + this.persistingMechanism.position = visibleData.showAtPosition; } this.resizableContentWidget.position = visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; - this.resizableContentWidget.preference = [this.renderingAbove]; this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + this.resizableContentWidget.getDomNode().style.position = 'fixed'; - this.resizableContentWidget.getDomNode().style.zIndex = '100'; + this.resizableContentWidget.getDomNode().style.zIndex = '50'; this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); - console.log('persistedSize : ', persistedSize); - if (!this.editor || !this.editor.hasModel()) { return; } @@ -336,6 +314,8 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.enableSashes(false, true, true, false); } + this.resizableContentWidget.preference = [this.renderingAbove]; + // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!persistedSize) { @@ -350,19 +330,6 @@ export class ResizableHoverWidget extends ResizableWidget { if (!this.visibleData) { return; } - - // TODO: add maybe - // this.editor.layoutContentWidget(this.resizableContentWidget); - // this.editor.render(); - - // const clientHeight = this.hoverWidget.containerDomNode.clientHeight; - // const clientWidth = this.hoverWidget.containerDomNode.clientWidth; - // this.element.layout(clientHeight, clientWidth); - - this.resizableContentWidget.preference = [this.renderingAbove]; - - console.log('this.renderingAbove : ', this.renderingAbove); - console.log('At the end of showAt'); } public override hide(): void { @@ -381,27 +348,24 @@ export class ResizableHoverWidget extends ResizableWidget { } } - public onContentsChanged(): void { // persistedSize?: dom.Dimension | undefined - - const persistedSize = this.resizableContentWidget.findPersistedSize(); + public onContentsChanged(): void { console.log('Inside of onContentsChanged'); + const persistedSize = this.resizableContentWidget.findPersistedSize(); const containerDomNode = this.getDomNode(); const contentsDomNode = this.getContentsDomNode(); // Suppose a persisted size is defined if (persistedSize) { - const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 7 - 7); // - SASH_WIDTH - // const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); - const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 7 - 7); // SASH_WIDTH + const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 7 - 7); + const height = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 7 - 7); - // Already setting directly the height and width parameters - containerDomNode.style.width = widthMinusSash + 'px'; - containerDomNode.style.height = heightMinusSash + 'px'; - contentsDomNode.style.width = widthMinusSash + 'px'; - contentsDomNode.style.height = heightMinusSash + 'px'; + containerDomNode.style.width = width + 'px'; + containerDomNode.style.height = height + 'px'; + contentsDomNode.style.width = width + 'px'; + contentsDomNode.style.height = height + 'px'; } else { @@ -420,18 +384,13 @@ export class ResizableHoverWidget extends ResizableWidget { const clientHeight = this.hoverWidget.containerDomNode.clientHeight; const clientWidth = this.hoverWidget.containerDomNode.clientWidth; - console.log('clientHeight: ', clientHeight); - console.log('clientWidth : ', clientWidth); this.element.layout(clientHeight + 7, clientWidth + 7); - // this.element.layout(clientHeight, clientWidth); const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - console.log('hasHorizontalScrollbar: ', hasHorizontalScrollbar); if (hasHorizontalScrollbar) { - // There is just a horizontal scrollbar const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { @@ -439,7 +398,8 @@ export class ResizableHoverWidget extends ResizableWidget { reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); - // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. + + // Need the following code in order to make the scrollbar visible when exact persisted size is used if (persistedSize && maxRenderingHeight) { containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9) + 'px'; // - SASH_WIDTH contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9 - SCROLLBAR_WIDTH) + 'px'; // - SASH_WIDTH @@ -451,23 +411,17 @@ export class ResizableHoverWidget extends ResizableWidget { if (persistedSize) { console.log('when using a persisted size'); this.element.layout(clientHeight + 17 - 6, clientWidth + 7); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - this.hoverWidget.onContentsChanged(); } else { console.log('Inside of the case when repositioning'); this.element.layout(clientHeight + 17, clientWidth + 7); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - this.hoverWidget.onContentsChanged(); } + + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + this.hoverWidget.onContentsChanged(); } } - console.log('this.resizableContentWidget : ', this.resizableContentWidget); - - // --- - console.log('Before changing the sash size'); const size = this.element.size; @@ -494,7 +448,6 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.eastSash.el.style.top = 2 + 'px'; this.element.westSash.el.style.top = 2 + 'px'; - // --- this.editor.layoutContentWidget(this.resizableContentWidget); } @@ -556,12 +509,14 @@ export class ResizableHoverWidget extends ResizableWidget { export class ResizableContentHoverWidget extends ResizableContentWidget { - public ID = 'editor.contrib.resizableContentHoverWidget'; - private hoverDisposables = new DisposableStore(); + public static ID = 'editor.contrib.resizableContentHoverWidget'; constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget, editor); - console.log('Inside of resizable content hover widget'); + } + + public getId(): string { + return ResizableContentHoverWidget.ID; } } From e7b44978da7c547d5799063484de8d37498fad01 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 13:54:05 +0200 Subject: [PATCH 28/72] changing pixel sizes, need to further improve pixel sizes --- src/vs/base/browser/ui/hover/hoverWidget.ts | 1 - .../contrib/hover/browser/contentHover.ts | 6 -- src/vs/editor/contrib/hover/browser/hover.ts | 6 +- .../hover/browser/resizableHoverWidget.ts | 78 +++++++++++-------- 4 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/vs/base/browser/ui/hover/hoverWidget.ts b/src/vs/base/browser/ui/hover/hoverWidget.ts index e57b1988cade7..96e99cbec4a2f 100644 --- a/src/vs/base/browser/ui/hover/hoverWidget.ts +++ b/src/vs/base/browser/ui/hover/hoverWidget.ts @@ -37,7 +37,6 @@ export class HoverWidget extends Disposable { consumeMouseWheelIfScrollbarIsNeeded: true })); this.containerDomNode.appendChild(this.scrollbar.getDomNode()); - this.containerDomNode.style.zIndex = '50'; } public onContentsChanged(): void { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 1d5b36c3dd345..83b8cabc29690 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -148,9 +148,6 @@ export class ContentHoverController extends Disposable { } if (!anchor) { - - console.log('no anchor'); - this._setCurrentResult(null); return false; } @@ -161,9 +158,6 @@ export class ContentHoverController extends Disposable { } if (!anchor.canAdoptVisibleHover(this._currentResult.anchor, this._widget.position)) { - - console.log('can not adopt visible hover'); - // The new anchor is not compatible with the previous anchor this._setCurrentResult(null); this._startHoverOperationIfNecessary(anchor, mode, source, focus, false); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 90fce0e8d75bb..210796373770c 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -31,6 +31,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ResizableContentHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; import * as nls from 'vs/nls'; import 'vs/css!./hover'; + export class ModesHoverController implements IEditorContribution { public static readonly ID = 'editor.contrib.hover'; @@ -168,11 +169,6 @@ export class ModesHoverController implements IEditorContribution { return; } - if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { - // mouse down on top of the content hover widget - return; - } - if (this._isHoverSticky && this._contentWidget?.isVisibleFromKeyboard()) { // Sticky mode is on and the hover has been shown via keyboard // so moving the mouse has no effect diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index d196c14e0e5e9..9582793c785c3 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -236,8 +236,9 @@ export class ResizableHoverWidget extends ResizableWidget { this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - this.resizableContentWidget.getDomNode().style.position = 'fixed'; - this.resizableContentWidget.getDomNode().style.zIndex = '50'; + const domNode = this.resizableContentWidget.getDomNode(); + domNode.style.position = 'fixed'; + domNode.style.zIndex = '50'; this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); @@ -253,9 +254,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.paddingBottom = ''; this._updateFont(); - const containerDomNode = this.resizableContentWidget.getDomNode(); let height; - // If the persisted size has already been found then set a maximum height and width if (!persistedSize) { this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; @@ -265,7 +264,7 @@ export class ResizableHoverWidget extends ResizableWidget { // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this.editor.render(); - height = containerDomNode.clientHeight; + height = domNode.clientHeight; } // When there is a persisted size then do not use a maximum height or width else { @@ -359,6 +358,8 @@ export class ResizableHoverWidget extends ResizableWidget { // Suppose a persisted size is defined if (persistedSize) { + console.log('Using persisted size'); + const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 7 - 7); const height = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 7 - 7); @@ -369,6 +370,8 @@ export class ResizableHoverWidget extends ResizableWidget { } else { + console.log('Not using persisted size'); + // Otherwise the height and width are set to auto containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; @@ -376,50 +379,63 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.height = 'auto'; } - containerDomNode.style.top = 2 + 'px'; - containerDomNode.style.left = 2 + 'px'; - this.editor.layoutContentWidget(this.resizableContentWidget); this.hoverWidget.onContentsChanged(); const clientHeight = this.hoverWidget.containerDomNode.clientHeight; const clientWidth = this.hoverWidget.containerDomNode.clientWidth; - this.element.layout(clientHeight + 7, clientWidth + 7); + this.element.layout(clientHeight + 6, clientWidth + 6); + containerDomNode.style.height = clientHeight + 'px'; + containerDomNode.style.width = clientWidth + 'px'; + containerDomNode.style.top = 2 + 'px'; + containerDomNode.style.left = 2 + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { + console.log('has horizontal scrollbar'); + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - let reposition = false; + // let reposition = false; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - reposition = true; + // reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); - // Need the following code in order to make the scrollbar visible when exact persisted size is used - if (persistedSize && maxRenderingHeight) { - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9) + 'px'; // - SASH_WIDTH - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 9 - SCROLLBAR_WIDTH) + 'px'; // - SASH_WIDTH - reposition = true; + if (!maxRenderingHeight) { + return; } - if (reposition) { - console.log('Inside of the case when repositioning'); - - if (persistedSize) { - console.log('when using a persisted size'); - this.element.layout(clientHeight + 17 - 6, clientWidth + 7); - } else { - console.log('Inside of the case when repositioning'); - this.element.layout(clientHeight + 17, clientWidth + 7); - } - - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - this.hoverWidget.onContentsChanged(); + + if (persistedSize) { // if (persistedSize && maxRenderingHeight) { + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6 - SCROLLBAR_WIDTH) + 'px'; + this.element.layout(clientHeight + 10 + 6, clientWidth + 6); + // reposition = true; + } else { + containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; + this.element.layout(clientHeight + 6, clientWidth + 6); } + // if (reposition) { + // console.log('Inside of the case when repositioning'); + // if (persistedSize) { + // console.log('when using a persisted size'); + // this.element.layout(clientHeight + 17 - 6, clientWidth + 7); + // } else { + // console.log('Inside of the case when repositioning'); + // this.element.layout(clientHeight + 10 + 6, clientWidth + 6); + // } + // this.editor.layoutContentWidget(this.resizableContentWidget); + // this.editor.render(); + // this.hoverWidget.onContentsChanged(); + // } + + this.editor.layoutContentWidget(this.resizableContentWidget); + // this.editor.render(); + this.hoverWidget.onContentsChanged(); } console.log('Before changing the sash size'); @@ -432,7 +448,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.northSash.el.style.left = 2 + 'px'; this.element.southSash.el.style.left = 2 + 'px'; - if (hasHorizontalScrollbar) { + if (hasHorizontalScrollbar && persistedSize) { height = clientHeight + 12; } else { height = clientHeight + 2; From 94ae3ac20adb81257b99069244236d6d10dab59f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 14:32:30 +0200 Subject: [PATCH 29/72] Adding a command in order to be able to clear the persisted hover sizes --- .../contrib/hover/browser/contentHover.ts | 4 +++ src/vs/editor/contrib/hover/browser/hover.ts | 30 +++++++++++++++++++ .../hover/browser/resizableContentWidget.ts | 13 ++++++-- .../hover/browser/resizableHoverWidget.ts | 10 +++++-- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 83b8cabc29690..036d8ff3616e1 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -391,6 +391,10 @@ export class ContentHoverController extends Disposable { public escape(): void { this._widget.escape(); } + + public clearPersistedSizes(): void { + this._widget?.clearPersistedSizes(); + } } class HoverResult { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 210796373770c..5b42fe2c50012 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -286,6 +286,10 @@ export class ModesHoverController implements IEditorContribution { return this._contentWidget?.isVisible(); } + public clearPersistedSizes(): void { + this._contentWidget?.clearPersistedSizes(); + } + public dispose(): void { this._unhookEvents(); this._toUnhook.dispose(); @@ -671,6 +675,31 @@ class EscapeFocusHoverAction extends EditorAction { } } +class ClearPersistedHoverSizes extends EditorAction { + + constructor() { + super({ + id: 'editor.action.clearPersistedHoverSizes', + label: nls.localize({ + key: 'clearPersistedHoverSizes', + comment: [ + 'Action that allows to clear the persisted hover sizes.' + ] + }, "Clear Persisted Hover Sizes"), + alias: 'Clear Persisted Hover Sizes', + precondition: undefined + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + const controller = ModesHoverController.get(editor); + if (!controller) { + return; + } + controller.clearPersistedSizes(); + } +} + registerEditorContribution(ModesHoverController.ID, ModesHoverController, EditorContributionInstantiation.BeforeFirstInteraction); registerEditorAction(ShowOrFocusHoverAction); registerEditorAction(ShowDefinitionPreviewHoverAction); @@ -683,6 +712,7 @@ registerEditorAction(PageDownHoverAction); registerEditorAction(GoToTopHoverAction); registerEditorAction(GoToBottomHoverAction); registerEditorAction(EscapeFocusHoverAction); +registerEditorAction(ClearPersistedHoverSizes); HoverParticipantRegistry.register(MarkdownHoverParticipant); HoverParticipantRegistry.register(MarkerHoverParticipant); diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 3d0318806342f..1926f827acfb7 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -78,9 +78,7 @@ export abstract class ResizableWidget implements IResizableWidget { this.disposables.dispose(); } - resize(dimension: dom.Dimension): void { - this.element.layout(dimension.height, dimension.width); - } + resize(dimension: dom.Dimension): void { } hide(): void { this.resizing = false; @@ -205,6 +203,7 @@ export class MultipleSizePersistingOptions implements IPersistingOptions { interface IPersistingMechanism extends IDisposable { findSize(): dom.Dimension | undefined; + clear(): void; } export class SingleSizePersistingMechanism implements IPersistingMechanism { @@ -259,6 +258,10 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { dispose(): void { this.disposables.dispose(); } + + clear(): void { + this.persistedWidgetSize?.reset(); + } } export class MultipleSizePersistingMechanism implements IPersistingMechanism { @@ -377,6 +380,10 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { dispose(): void { this.disposables.dispose(); } + + clear(): void { + this.persistedWidgetSizes.clear(); + } } class PersistedWidgetSize { diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 9582793c785c3..7bf33a2b11b0f 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -86,13 +86,15 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; // TODO: Change the pixel sizes - const width = size.width - 7 + 'px'; + const width = size.width + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; - const height = size.height - 7 + 'px'; + const height = size.height + 'px'; this.hoverWidget.containerDomNode.style.height = height; this.hoverWidget.contentsDomNode.style.height = height; + // this.element.layout(size.height + 6, size.width + 6); + const sashWidth = size.width - 5 + 'px'; const sashHeight = size.height - 5 + 'px'; this.element.northSash.el.style.width = sashWidth; @@ -521,6 +523,10 @@ export class ResizableHoverWidget extends ResizableWidget { public escape(): void { this.editor.focus(); } + + public clearPersistedSizes(): void { + this.persistingMechanism.clear(); + } } export class ResizableContentHoverWidget extends ResizableContentWidget { From 73737cd042f051274b31736cd4d28d535f4275ac Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 15:15:04 +0200 Subject: [PATCH 30/72] works on hovers with horizontal scroll-bar, find why does not work with hovers with no initial horizontal scrollbar --- .../hover/browser/resizableHoverWidget.ts | 93 ++++++------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 7bf33a2b11b0f..7ce985a3be820 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -86,36 +86,35 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; // TODO: Change the pixel sizes - const width = size.width + 'px'; + const width = size.width - 6 + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; - const height = size.height + 'px'; + const height = size.height - 6 + 'px'; this.hoverWidget.containerDomNode.style.height = height; this.hoverWidget.contentsDomNode.style.height = height; - // this.element.layout(size.height + 6, size.width + 6); - - const sashWidth = size.width - 5 + 'px'; - const sashHeight = size.height - 5 + 'px'; - this.element.northSash.el.style.width = sashWidth; - this.element.southSash.el.style.width = sashWidth; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - this.element.eastSash.el.style.height = sashHeight; - this.element.westSash.el.style.height = sashHeight; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; + this.element.northSash.el.style.width = width; + this.element.southSash.el.style.width = width; + this.element.northSash.el.style.left = 3 + 'px'; + this.element.southSash.el.style.left = 3 + 'px'; + this.element.eastSash.el.style.height = height; + this.element.westSash.el.style.height = height; + this.element.eastSash.el.style.top = 3 + 'px'; + this.element.westSash.el.style.top = 3 + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { + + console.log('has horizontal scrollbar in the resize function'); + // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 7 + 'px'; + this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 6 + 'px'; } this.hoverWidget.scrollbar.scanDomNode(); @@ -362,8 +361,8 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('Using persisted size'); - const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 7 - 7); - const height = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 7 - 7); + const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 6); + const height = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 6); containerDomNode.style.width = width + 'px'; containerDomNode.style.height = height + 'px'; @@ -374,7 +373,6 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('Not using persisted size'); - // Otherwise the height and width are set to auto containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; contentsDomNode.style.width = 'auto'; @@ -384,8 +382,8 @@ export class ResizableHoverWidget extends ResizableWidget { this.editor.layoutContentWidget(this.resizableContentWidget); this.hoverWidget.onContentsChanged(); - const clientHeight = this.hoverWidget.containerDomNode.clientHeight; - const clientWidth = this.hoverWidget.containerDomNode.clientWidth; + const clientHeight = containerDomNode.clientHeight; + const clientWidth = containerDomNode.clientWidth; this.element.layout(clientHeight + 6, clientWidth + 6); containerDomNode.style.height = clientHeight + 'px'; @@ -400,10 +398,8 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('has horizontal scrollbar'); const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - // let reposition = false; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - // reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); @@ -411,61 +407,32 @@ export class ResizableHoverWidget extends ResizableWidget { return; } - if (persistedSize) { // if (persistedSize && maxRenderingHeight) { + if (persistedSize) { containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6) + 'px'; contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6 - SCROLLBAR_WIDTH) + 'px'; - this.element.layout(clientHeight + 10 + 6, clientWidth + 6); - // reposition = true; } else { containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; - this.element.layout(clientHeight + 6, clientWidth + 6); } - // if (reposition) { - // console.log('Inside of the case when repositioning'); - // if (persistedSize) { - // console.log('when using a persisted size'); - // this.element.layout(clientHeight + 17 - 6, clientWidth + 7); - // } else { - // console.log('Inside of the case when repositioning'); - // this.element.layout(clientHeight + 10 + 6, clientWidth + 6); - // } - // this.editor.layoutContentWidget(this.resizableContentWidget); - // this.editor.render(); - // this.hoverWidget.onContentsChanged(); - // } - + this.element.layout(clientHeight + 6, clientWidth + 6); this.editor.layoutContentWidget(this.resizableContentWidget); - // this.editor.render(); this.hoverWidget.onContentsChanged(); } console.log('Before changing the sash size'); - const size = this.element.size; - let height = size.height; - const width = size.width; - this.element.northSash.el.style.width = width - 4 + 'px'; - this.element.southSash.el.style.width = width - 4 + 'px'; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - - if (hasHorizontalScrollbar && persistedSize) { - height = clientHeight + 12; - } else { - height = clientHeight + 2; - } + const finalClientHeight = containerDomNode.clientHeight; + const finalClientWidth = containerDomNode.clientWidth; - if (!persistedSize) { - this.element.eastSash.el.style.height = height + 'px'; - this.element.westSash.el.style.height = height + 'px'; - } else { - this.element.eastSash.el.style.height = height - 5 + 'px'; - this.element.westSash.el.style.height = height - 5 + 'px'; - } + this.element.northSash.el.style.width = finalClientWidth + 'px'; + this.element.southSash.el.style.width = finalClientWidth + 'px'; + this.element.northSash.el.style.left = 3 + 'px'; + this.element.southSash.el.style.left = 3 + 'px'; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; + this.element.eastSash.el.style.height = finalClientHeight + 'px'; + this.element.westSash.el.style.height = finalClientHeight + 'px'; + this.element.eastSash.el.style.top = 3 + 'px'; + this.element.westSash.el.style.top = 3 + 'px'; this.editor.layoutContentWidget(this.resizableContentWidget); } From b7f7c5cf9919db65a584d2e8340bd4658d4e45ac Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 15:49:33 +0200 Subject: [PATCH 31/72] got rid of flickering with the help of an additional boolean --- src/vs/editor/contrib/hover/browser/contentHover.ts | 5 +++++ src/vs/editor/contrib/hover/browser/hover.ts | 1 + .../contrib/hover/browser/resizableHoverWidget.ts | 12 ++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 036d8ff3616e1..2b44d564d8857 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -81,6 +81,7 @@ export class ContentHoverController extends Disposable { */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { + console.log('Inside of maybeShowAt'); // While the hover overlay is resizing, the hover is showing if (this._widget.isResizing()) { return true; @@ -126,6 +127,8 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ private _startShowingOrUpdateHover(anchor: HoverAnchor | null, mode: HoverStartMode, source: HoverStartSource, focus: boolean, mouseEvent: IEditorMouseEvent | null): boolean { + console.log('Inside of _startShowOrUpdateHover'); + if (!this._widget.position || !this._currentResult) { // The hover is not visible if (anchor) { @@ -186,6 +189,7 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { + console.log('Inside of _setCurrentResult'); if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -238,6 +242,7 @@ export class ContentHoverController extends Disposable { } private _withResult(hoverResult: HoverResult): void { + console.log('Inside of _withResult'); if (this._widget.position && this._currentResult && this._currentResult.isComplete) { // The hover is visible with a previous complete result. diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 5b42fe2c50012..6f8fef428ffa5 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -140,6 +140,7 @@ export class ModesHoverController implements IEditorContribution { } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { + console.log('mouseEvent : ', mouseEvent); const target = mouseEvent.target; if (this._isMouseDown && this._hoverClicked) { diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 7ce985a3be820..8573dc2a11137 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -26,6 +26,7 @@ export class ResizableHoverWidget extends ResizableWidget { private resizableContentWidget: ResizableContentHoverWidget; private visibleData: ContentHoverVisibleData | null = null; private renderingAbove: ContentWidgetPositionPreference; + private visible: boolean = false; public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); public readonly allowEditorOverflow = true; @@ -230,6 +231,8 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + console.log('Inside of showAt'); + if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { this.persistingMechanism.position = visibleData.showAtPosition; } @@ -240,7 +243,10 @@ export class ResizableHoverWidget extends ResizableWidget { const domNode = this.resizableContentWidget.getDomNode(); domNode.style.position = 'fixed'; domNode.style.zIndex = '50'; - this.editor.addContentWidget(this.resizableContentWidget); + + if (!this.visible) { + this.editor.addContentWidget(this.resizableContentWidget); + } const persistedSize = this.findPersistedSize(); @@ -330,12 +336,14 @@ export class ResizableHoverWidget extends ResizableWidget { if (!this.visibleData) { return; } + + this.visible = true; } public override hide(): void { console.log('Inside of hide of ResizableHoverWidget'); - + this.visible = false; this.element.clearSashHoverState(); this.editor.removeContentWidget(this.resizableContentWidget); if (this.visibleData) { From b027af8b710bf685f3ab53cfdc84c9d0de647d93 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 4 Apr 2023 20:25:45 +0200 Subject: [PATCH 32/72] chaning the lengths of the sashes in order for it to cover the right lengths --- .../hover/browser/resizableHoverWidget.ts | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 8573dc2a11137..baf6c1771c508 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -94,14 +94,16 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.containerDomNode.style.height = height; this.hoverWidget.contentsDomNode.style.height = height; - this.element.northSash.el.style.width = width; - this.element.southSash.el.style.width = width; - this.element.northSash.el.style.left = 3 + 'px'; - this.element.southSash.el.style.left = 3 + 'px'; - this.element.eastSash.el.style.height = height; - this.element.westSash.el.style.height = height; - this.element.eastSash.el.style.top = 3 + 'px'; - this.element.westSash.el.style.top = 3 + 'px'; + const horizontalSashLength = size.width - 4 + 'px'; + this.element.northSash.el.style.width = horizontalSashLength; + this.element.southSash.el.style.width = horizontalSashLength; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; + const verticalSashLength = size.height - 4 + 'px'; + this.element.eastSash.el.style.height = verticalSashLength; + this.element.westSash.el.style.height = verticalSashLength; + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); @@ -429,18 +431,18 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('Before changing the sash size'); - const finalClientHeight = containerDomNode.clientHeight; - const finalClientWidth = containerDomNode.clientWidth; + const finalClientHeight = containerDomNode.clientHeight + 2; + const finalClientWidth = containerDomNode.clientWidth + 2; this.element.northSash.el.style.width = finalClientWidth + 'px'; this.element.southSash.el.style.width = finalClientWidth + 'px'; - this.element.northSash.el.style.left = 3 + 'px'; - this.element.southSash.el.style.left = 3 + 'px'; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; this.element.eastSash.el.style.height = finalClientHeight + 'px'; this.element.westSash.el.style.height = finalClientHeight + 'px'; - this.element.eastSash.el.style.top = 3 + 'px'; - this.element.westSash.el.style.top = 3 + 'px'; + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; this.editor.layoutContentWidget(this.resizableContentWidget); } From dbaa9f8c5991b33913479c1bbf2d126f09977b45 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 11:23:56 +0200 Subject: [PATCH 33/72] adding 7 to the maximum height in order to remove unexpected resizing --- src/vs/base/browser/ui/resizable/resizable.ts | 11 +++++++ .../contrib/hover/browser/contentHover.ts | 8 ++--- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- .../hover/browser/resizableContentWidget.ts | 6 ++++ .../hover/browser/resizableHoverWidget.ts | 33 ++++++++++++++++--- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index 9bd5f4ff54219..66df8154208ed 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -135,17 +135,28 @@ export class ResizableHTMLElement { layout(height: number = this.size.height, width: number = this.size.width): void { + console.log('Inside of layout'); + console.log('height : ', height); + console.log('width : ', width); + const { height: minHeight, width: minWidth } = this._minSize; const { height: maxHeight, width: maxWidth } = this._maxSize; + console.log('minHeight : ', minHeight); + console.log('maxHeight : ', maxHeight); + height = Math.max(minHeight, Math.min(maxHeight, height)); width = Math.max(minWidth, Math.min(maxWidth, width)); const newSize = new Dimension(width, height); + console.log('newSize : ', newSize); + console.log('this._size : ', this._size); + if (!Dimension.equals(newSize, this._size)) { this.domNode.style.height = height + 'px'; this.domNode.style.width = width + 'px'; this._size = newSize; + console.log('this._size : ', this._size); this._northSash.layout(); this._eastSash.layout(); this._southSash.layout(); diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 2b44d564d8857..956a6f338a9b5 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -81,7 +81,7 @@ export class ContentHoverController extends Disposable { */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { - console.log('Inside of maybeShowAt'); + // console.log('Inside of maybeShowAt'); // While the hover overlay is resizing, the hover is showing if (this._widget.isResizing()) { return true; @@ -127,7 +127,7 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ private _startShowingOrUpdateHover(anchor: HoverAnchor | null, mode: HoverStartMode, source: HoverStartSource, focus: boolean, mouseEvent: IEditorMouseEvent | null): boolean { - console.log('Inside of _startShowOrUpdateHover'); + // console.log('Inside of _startShowOrUpdateHover'); if (!this._widget.position || !this._currentResult) { // The hover is not visible @@ -189,7 +189,7 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { - console.log('Inside of _setCurrentResult'); + // console.log('Inside of _setCurrentResult'); if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -242,7 +242,7 @@ export class ContentHoverController extends Disposable { } private _withResult(hoverResult: HoverResult): void { - console.log('Inside of _withResult'); + // console.log('Inside of _withResult'); if (this._widget.position && this._currentResult && this._currentResult.isComplete) { // The hover is visible with a previous complete result. diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 6f8fef428ffa5..fe1d9970ac9c5 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -140,7 +140,7 @@ export class ModesHoverController implements IEditorContribution { } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { - console.log('mouseEvent : ', mouseEvent); + // console.log('mouseEvent : ', mouseEvent); const target = mouseEvent.target; if (this._isMouseDown && this._hoverClicked) { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 1926f827acfb7..747d41ccaae43 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -308,6 +308,7 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { this.disposables.add(this.resizableWidget.element.onDidResize(e => { console.log('Inside of on did resize of the multiple size persisting mechanism'); + console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); console.log('e : ', e); const height = e.dimension.height; @@ -315,9 +316,14 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { this.resizableWidget.resize(new dom.Dimension(width, height)); + console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); + const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); + console.log('maxRenderingWidth : ', maxRenderingWidth); + console.log('maxRenderingHeight : ', maxRenderingHeight); + if (!maxRenderingWidth || !maxRenderingHeight) { return; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index baf6c1771c508..9dcf44a9e78fe 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -90,9 +90,11 @@ export class ResizableHoverWidget extends ResizableWidget { const width = size.width - 6 + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; - const height = size.height - 6 + 'px'; - this.hoverWidget.containerDomNode.style.height = height; - this.hoverWidget.contentsDomNode.style.height = height; + + // TODO: There are issues with this part + // const height = size.height - 6 + 'px'; + // this.hoverWidget.containerDomNode.style.height = height; + // this.hoverWidget.contentsDomNode.style.height = height; const horizontalSashLength = size.width - 4 + 'px'; this.element.northSash.el.style.width = horizontalSashLength; @@ -117,11 +119,32 @@ export class ResizableHoverWidget extends ResizableWidget { if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } + this.hoverWidget.containerDomNode.style.height = size.height - 6 + 'px'; this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 6 + 'px'; + } else { + + console.log('Does not have horizontal scrollbar in the resize function'); + // TODO: There is still an error, why does the size change before event resize is called? + this.hoverWidget.containerDomNode.style.height = size.height - 6 + 'px'; + this.hoverWidget.contentsDomNode.style.height = size.height - 6 + 'px'; + // this.hoverWidget.contentsDomNode.style.height = size.height + 'px'; + this.element.layout(size.height, size.width); } + // const maximumRenderingWidth = this.findMaximumRenderingWidth(); + // const maximumRenderingHeight = this.findMaximumRenderingHeight(); + // console.log('maximumRenderingWidth : ', maximumRenderingWidth); + // console.log('maximumRenderingHeight : ', maximumRenderingHeight); + // if (!maximumRenderingWidth || !maximumRenderingHeight) { + // return; + // } + // this.element.maxSize = new dom.Dimension(maximumRenderingWidth, maximumRenderingHeight); + this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + + console.log('this.resizableWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); } public override findMaximumRenderingHeight(): number | undefined { @@ -141,7 +164,7 @@ export class ResizableHoverWidget extends ResizableWidget { availableSpace = bodyBox.height - mouseBottom; } - let divMaxHeight = 0; + let divMaxHeight = 7; for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } @@ -156,7 +179,7 @@ export class ResizableHoverWidget extends ResizableWidget { return Math.min(availableSpace, divMaxHeight); } - public findMaxRenderingWidth(): number | undefined { + public override findMaximumRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; } From ce7edf5d5c6d4b41e2e8293b11c89f842236a3b3 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 11:28:28 +0200 Subject: [PATCH 34/72] resetting the maximum rendering height when hiding the content widget --- src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 9dcf44a9e78fe..3254740e00a22 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -369,6 +369,7 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('Inside of hide of ResizableHoverWidget'); this.visible = false; + this.element.maxSize = new dom.Dimension(Infinity, Infinity); this.element.clearSashHoverState(); this.editor.removeContentWidget(this.resizableContentWidget); if (this.visibleData) { From 06e49a3f7abeae7ec139da9a38610f23e16344a4 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 12:02:57 +0200 Subject: [PATCH 35/72] separating into maximum rendering height and available space --- src/vs/base/browser/ui/resizable/resizable.ts | 3 +- .../hover/browser/resizableHoverWidget.ts | 29 +++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index 66df8154208ed..b4d5819d14dc9 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -156,12 +156,13 @@ export class ResizableHTMLElement { this.domNode.style.height = height + 'px'; this.domNode.style.width = width + 'px'; this._size = newSize; - console.log('this._size : ', this._size); this._northSash.layout(); this._eastSash.layout(); this._southSash.layout(); this._westSash.layout(); } + + console.log('this._size : ', this._size); } clearSashHoverState(): void { diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts index 3254740e00a22..419b608c60d64 100644 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts @@ -147,8 +147,7 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('this.resizableWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); } - public override findMaximumRenderingHeight(): number | undefined { - + public findAvailableSpace(): number | undefined { if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { return; } @@ -164,8 +163,21 @@ export class ResizableHoverWidget extends ResizableWidget { availableSpace = bodyBox.height - mouseBottom; } + return availableSpace; + } + + public override findMaximumRenderingHeight(): number | undefined { + + const availableSpace = this.findAvailableSpace(); + if (!availableSpace) { + return; + } + let divMaxHeight = 7; for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { + console.log('childHTMLElement : ', childHtmlElement); + console.log('childHTMLElement.innerHTML : ', childHtmlElement.innerHTML); + console.log('childHtmlElement.clientHeight : ', childHtmlElement.clientHeight); divMaxHeight += childHtmlElement.clientHeight; } @@ -394,15 +406,25 @@ export class ResizableHoverWidget extends ResizableWidget { if (persistedSize) { console.log('Using persisted size'); + console.log('persistedSize.height: ' + persistedSize.height); + console.log('persistedSize.width: ' + persistedSize.width); + + console.log('this.findMaximumRenderingWidth() : ', this.findMaximumRenderingWidth()); + console.log('this.findMaximumRenderingHeight() : ', this.findMaximumRenderingHeight()); const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 6); - const height = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height - 6); + const height = Math.min(this.findAvailableSpace() ?? Infinity, persistedSize.height - 6); + + console.log('width : ', width); + console.log('height : ', height); containerDomNode.style.width = width + 'px'; containerDomNode.style.height = height + 'px'; contentsDomNode.style.width = width + 'px'; contentsDomNode.style.height = height + 'px'; + this.element.layout(persistedSize.height, persistedSize.width); + } else { console.log('Not using persisted size'); @@ -469,6 +491,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.westSash.el.style.top = 2 + 'px'; this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); } public clear(): void { From 1bc94f90ff06db2031ed4d8d41f98a227eb2ad32 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 15:57:43 +0200 Subject: [PATCH 36/72] adding the very high element width and height initially in order to allow resizing of children to whichever size --- src/vs/base/browser/ui/resizable/resizable.ts | 17 +- .../contrib/hover/browser/contentHover.ts | 607 +++++++++++++++++- src/vs/editor/contrib/hover/browser/hover.ts | 3 +- .../hover/browser/resizableContentWidget.ts | 4 - .../hover/browser/resizableHoverWidget.ts | 593 ----------------- 5 files changed, 600 insertions(+), 624 deletions(-) delete mode 100644 src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index b4d5819d14dc9..e53a6542724a7 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -135,23 +135,13 @@ export class ResizableHTMLElement { layout(height: number = this.size.height, width: number = this.size.width): void { - console.log('Inside of layout'); - console.log('height : ', height); - console.log('width : ', width); - const { height: minHeight, width: minWidth } = this._minSize; const { height: maxHeight, width: maxWidth } = this._maxSize; - console.log('minHeight : ', minHeight); - console.log('maxHeight : ', maxHeight); - height = Math.max(minHeight, Math.min(maxHeight, height)); width = Math.max(minWidth, Math.min(maxWidth, width)); const newSize = new Dimension(width, height); - console.log('newSize : ', newSize); - console.log('this._size : ', this._size); - if (!Dimension.equals(newSize, this._size)) { this.domNode.style.height = height + 'px'; this.domNode.style.width = width + 'px'; @@ -161,8 +151,6 @@ export class ResizableHTMLElement { this._southSash.layout(); this._westSash.layout(); } - - console.log('this._size : ', this._size); } clearSashHoverState(): void { @@ -176,6 +164,11 @@ export class ResizableHTMLElement { return this._size; } + set size(size: Dimension) { + this._size = size; + } + + set maxSize(value: Dimension) { this._maxSize = value; } diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 956a6f338a9b5..011047bcccaba 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -4,16 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { HoverAction } from 'vs/base/browser/ui/hover/hoverWidget'; +import { HoverAction, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { coalesce } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { IModelDecoration } from 'vs/editor/common/model'; +import { IModelDecoration, PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { TokenizationRegistry } from 'vs/editor/common/languages'; import { HoverOperation, HoverStartMode, HoverStartSource, IHoverComputer } from 'vs/editor/contrib/hover/browser/hoverOperation'; @@ -21,8 +21,9 @@ import { HoverAnchor, HoverAnchorType, HoverParticipantRegistry, HoverRangeAncho import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { AsyncIterableObject } from 'vs/base/common/async'; -import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; - +import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; const $ = dom.$; export class ContentHoverController extends Disposable { @@ -80,9 +81,6 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { - - // console.log('Inside of maybeShowAt'); - // While the hover overlay is resizing, the hover is showing if (this._widget.isResizing()) { return true; } @@ -127,8 +125,6 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ private _startShowingOrUpdateHover(anchor: HoverAnchor | null, mode: HoverStartMode, source: HoverStartSource, focus: boolean, mouseEvent: IEditorMouseEvent | null): boolean { - // console.log('Inside of _startShowOrUpdateHover'); - if (!this._widget.position || !this._currentResult) { // The hover is not visible if (anchor) { @@ -189,7 +185,6 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { - // console.log('Inside of _setCurrentResult'); if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -242,7 +237,6 @@ export class ContentHoverController extends Disposable { } private _withResult(hoverResult: HoverResult): void { - // console.log('Inside of _withResult'); if (this._widget.position && this._currentResult && this._currentResult.isComplete) { // The hover is visible with a previous complete result. @@ -453,6 +447,585 @@ class ContentHoverVisibleData { ) { } } +const SCROLLBAR_WIDTH = 10; +const SASH_WIDTH_MINUS_BORDER = 3; +const BORDER_WIDTH = 1; +const DELTA_SASH_LENGTH = 4; + +export class ResizableHoverWidget extends ResizableWidget { + + private disposableStore = new DisposableStore(); + private resizableContentWidget: ResizableContentHoverWidget; + private visibleData: ContentHoverVisibleData | null = null; + private renderingAbove: ContentWidgetPositionPreference; + private visible: boolean = false; + + public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); + public readonly allowEditorOverflow = true; + private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); + private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); + private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.getDomNode())); + private readonly horizontalScrollingBy: number = 30; + + constructor( + editor: ICodeEditor, + @IContextKeyService private readonly contextKeyService: IContextKeyService + ) { + super(editor, new MultipleSizePersistingOptions()); + this.element.domNode.style.position = 'absolute'; + this.element.domNode.style.zIndex = '50'; + dom.append(this.element.domNode, this.hoverWidget.containerDomNode); + + this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); + this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); + this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { + this._updateFont(); + } + })); + this.disposableStore.add(this.focusTracker.onDidFocus(() => { + this.hoverFocusedKey.set(true); + })); + this.disposableStore.add(this.focusTracker.onDidBlur(() => { + this.hoverFocusedKey.set(false); + })); + this._setVisibleData(null); + this._layout(); + } + + public get position(): Position | null { + return this.visibleData?.showAtPosition ?? null; + } + + public get isColorPickerVisible(): boolean { + return Boolean(this.visibleData?.colorPicker); + } + + public get isVisibleFromKeyboard(): boolean { + return (this.visibleData?.source === HoverStartSource.Keyboard); + } + + public get isVisible(): boolean { + return this.hoverVisibleKey.get() ?? false; + } + + public override resize(size: dom.Dimension) { + + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + + const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; + this.element.northSash.el.style.width = horizontalSashLength; + this.element.southSash.el.style.width = horizontalSashLength; + this.element.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this.element.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; + this.element.eastSash.el.style.height = verticalSashLength; + this.element.westSash.el.style.height = verticalSashLength; + this.element.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.element.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + + const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.hoverWidget.containerDomNode.style.width = width; + this.hoverWidget.contentsDomNode.style.width = width; + + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + + if (hasHorizontalScrollbar) { + // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + } + this.hoverWidget.containerDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + } else { + this.hoverWidget.containerDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.hoverWidget.contentsDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + } + + this.hoverWidget.scrollbar.scanDomNode(); + this.editor.layoutContentWidget(this.resizableContentWidget); + } + + public findAvailableSpaceVertically(): number | undefined { + if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); + const bodyBox = dom.getClientArea(document.body); + let availableSpace: number; + + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + availableSpace = editorBox.top + mouseBox.top - 30; + } else { + const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; + availableSpace = bodyBox.height - mouseBottom; + } + + return availableSpace; + } + + public findAvailableSpaceHorizontally(): number | undefined { + return this.findMaximumRenderingWidth(); + } + + public override findMaximumRenderingHeight(): number | undefined { + + const availableSpace = this.findAvailableSpaceVertically(); + if (!availableSpace) { + return; + } + + let divMaxHeight = 2 * SASH_WIDTH_MINUS_BORDER + 1; + for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { + divMaxHeight += childHtmlElement.clientHeight; + } + + if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { + divMaxHeight += SCROLLBAR_WIDTH; + } + + return Math.min(availableSpace, divMaxHeight); + } + + // Here findMaximumRenderingWidth and findAvailableSpaceHorizontally are the same + public override findMaximumRenderingWidth(): number | undefined { + if (!this.editor || !this.editor.hasModel()) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const widthOfEditor = editorBox.width; + const leftOfEditor = editorBox.left; + const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; + const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; + return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; + } + + public override dispose(): void { + this.editor.removeContentWidget(this.resizableContentWidget); + if (this.visibleData) { + this.visibleData.disposables.dispose(); + } + super.dispose(); + } + + public getDomNode() { + return this.hoverWidget.containerDomNode; + } + + public getContentsDomNode() { + return this.hoverWidget.contentsDomNode; + } + + public isMouseGettingCloser(posx: number, posy: number): boolean { + if (!this.visibleData) { + return false; + } + if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { + this.visibleData.initialMousePosX = posx; + this.visibleData.initialMousePosY = posy; + return false; + } + + const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); + if (typeof this.visibleData.closestMouseDistance === 'undefined') { + this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + } + const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + // The mouse is getting farther away + return false; + } + this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); + return true; + } + + private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { + if (this.visibleData) { + this.visibleData.disposables.dispose(); + } + this.visibleData = visibleData; + this.hoverVisibleKey.set(!!this.visibleData); + this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); + } + + private _layout(): void { + const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); + const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); + + this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; + this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + } + + private _updateFont(): void { + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); + codeClasses.forEach(node => this.editor.applyFontInfo(node)); + } + + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + + console.log('Inside of showAt'); + + let clientHeight; + let clientWidth; + const containerDomNode = this.getDomNode(); + + if (!this.editor || !this.editor.hasModel()) { + return; + } + + if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { + this.persistingMechanism.position = visibleData.showAtPosition; + } + this.resizableContentWidget.position = visibleData.showAtPosition; + this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; + this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + // const resizableContent = this.resizableContentWidget.getDomNode(); + // resizableContent.style.width = 'auto'; + // resizableContent.style.height = 'auto'; + this._setVisibleData(visibleData); + + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + console.log('Before adding content widget'); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + + if (!this.visible) { + this.editor.addContentWidget(this.resizableContentWidget); + } + + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + console.log('After adding content widget'); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + + const persistedSize = this.findPersistedSize(); + this.hoverWidget.contentsDomNode.textContent = ''; + this.hoverWidget.contentsDomNode.appendChild(node); + this.hoverWidget.contentsDomNode.style.paddingBottom = ''; + this._updateFont(); + + let height; + + // If there is no persisted size, then do normal rendering + if (!persistedSize) { + this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + + // this.hoverWidget.containerDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + // this.hoverWidget.containerDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this.editor.render(); + height = this.resizableContentWidget.getDomNode().clientHeight + 6; + } + // When there is a persisted size then do not use a maximum height or width + else { + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + height = persistedSize.height; + } + + // The dimensions of the document in which we are displaying the hover + const bodyBox = dom.getClientArea(document.body); + // Hard-coded in the hover.css file as 1.5em or 24px + const minHeight = 24; + // The full height is already passed in as a parameter + const fullHeight = height; + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); + // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height + const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; + // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position + const availableSpaceBelow = bodyBox.height - mouseBottom; + // Max height below is the minimum of the available space below and the full height of the widget + const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); + // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor + const availableSpaceAbove = editorBox.top + mouseBox.top - 30; + const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); + // We find the maximum height of the widget possible on the top or on the bottom + const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); + + if (height < minHeight) { + height = minHeight; + } + if (height > maxHeight) { + height = maxHeight; + } + + // Determining whether we should render above or not ideally + if (this.editor.getOption(EditorOption.hover).above) { + this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + } else { + this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + } + + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + this.element.enableSashes(true, true, false, false); + } else { + this.element.enableSashes(false, true, true, false); + } + + this.resizableContentWidget.preference = [this.renderingAbove]; + + // See https://github.com/microsoft/vscode/issues/140339 + // TODO: Doing a second layout of the hover after force rendering the editor + if (!persistedSize) { + this.onContentsChanged(); + } + + if (visibleData.stoleFocus) { + this.hoverWidget.containerDomNode.focus(); + } + visibleData.colorPicker?.layout(); + this.visible = true; + } + + public override hide(): void { + this.visible = false; + this.element.maxSize = new dom.Dimension(Infinity, Infinity); + this.element.clearSashHoverState(); + this.editor.removeContentWidget(this.resizableContentWidget); + if (this.visibleData) { + const stoleFocus = this.visibleData.stoleFocus; + this._setVisibleData(null); + this.editor.layoutContentWidget(this.resizableContentWidget); + if (stoleFocus) { + this.editor.focus(); + } + } + } + + public onContentsChanged(): void { + + let clientHeight; + let clientWidth; + let resizableClientHeight; + let resizableClientWidth; + + console.log('inside of on contents changed'); + console.log('this.resizableContentWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); + + const persistedSize = this.resizableContentWidget.findPersistedSize(); + // const resizableContent = this.resizableContentWidget.getDomNode(); + const containerDomNode = this.getDomNode(); + const contentsDomNode = this.getContentsDomNode(); + const resizableContentDomNode = this.resizableContentWidget.getDomNode(); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + + // Suppose a persisted size is defined + if (persistedSize) { + const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 6); + const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 6); + containerDomNode.style.width = width + 'px'; + containerDomNode.style.height = height + 'px'; + contentsDomNode.style.width = width + 'px'; + contentsDomNode.style.height = height + 'px'; + // this.element.layout(persistedSize.height, persistedSize.width); + } else { + + console.log('Not using persisted size'); + containerDomNode.style.width = 'auto'; + containerDomNode.style.height = 'auto'; + contentsDomNode.style.width = 'auto'; + contentsDomNode.style.height = 'auto'; + + // --- + this.element.domNode.style.width = 100000 + 'px'; + this.element.domNode.style.height = 100000 + 'px'; + } + + console.log('Before layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + + this.editor.layoutContentWidget(this.resizableContentWidget); + this.hoverWidget.onContentsChanged(); + + console.log('After layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + + this.element.layout(clientHeight + 6, clientWidth + 6); + // --- + this.element.domNode.style.width = clientWidth + 6 + 'px'; + this.element.domNode.style.height = clientHeight + 6 + 'px'; + // --- + containerDomNode.style.height = clientHeight + 'px'; + containerDomNode.style.width = clientWidth + 'px'; + containerDomNode.style.top = 2 + 'px'; + containerDomNode.style.left = 2 + 'px'; + + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + + if (hasHorizontalScrollbar) { + console.log('has horizontal scrollbar'); + + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + } + const maxRenderingHeight = this.findMaximumRenderingHeight(); + + if (!maxRenderingHeight) { + return; + } + + if (persistedSize) { + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6 - SCROLLBAR_WIDTH) + 'px'; + } else { + containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; + } + this.element.layout(clientHeight + 6, clientWidth + 6); + this.editor.layoutContentWidget(this.resizableContentWidget); + this.hoverWidget.onContentsChanged(); + } + + console.log('Before changing the sash size'); + + const finalClientHeight = containerDomNode.clientHeight + 2; + const finalClientWidth = containerDomNode.clientWidth + 2; + + this.element.northSash.el.style.width = finalClientWidth + 'px'; + this.element.southSash.el.style.width = finalClientWidth + 'px'; + this.element.northSash.el.style.left = 2 + 'px'; + this.element.southSash.el.style.left = 2 + 'px'; + + this.element.eastSash.el.style.height = finalClientHeight + 'px'; + this.element.westSash.el.style.height = finalClientHeight + 'px'; + this.element.eastSash.el.style.top = 2 + 'px'; + this.element.westSash.el.style.top = 2 + 'px'; + + this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.render(); + + console.log('At the end of on contents changed'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + } + + public clear(): void { + this.hoverWidget.contentsDomNode.textContent = ''; + } + + public focus(): void { + this.hoverWidget.containerDomNode.focus(); + } + + public scrollUp(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); + } + + public scrollDown(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); + } + + public scrollLeft(): void { + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); + } + + public scrollRight(): void { + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); + } + + public pageUp(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); + } + + public pageDown(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); + } + + public goToTop(): void { + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); + } + + public goToBottom(): void { + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); + } + + public escape(): void { + this.editor.focus(); + } + + public clearPersistedSizes(): void { + this.persistingMechanism.clear(); + } +} + +export class ResizableContentHoverWidget extends ResizableContentWidget { + + public static ID = 'editor.contrib.resizableContentHoverWidget'; + + constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { + super(resizableHoverWidget, editor); + } + + public getId(): string { + return ResizableContentHoverWidget.ID; + } +} + class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { public readonly hoverElement: HTMLElement; @@ -578,3 +1151,11 @@ class ContentHoverComputer implements IHoverComputer { return coalesce(result); } } + +function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { + const x = (left + width / 2); // x center of rectangle + const y = (top + height / 2); // y center of rectangle + const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); + const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); + return Math.sqrt(dx * dx + dy * dy); +} diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index fe1d9970ac9c5..ee5e73f00e242 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -15,7 +15,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition'; import { HoverStartMode, HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { ContentHoverController } from 'vs/editor/contrib/hover/browser/contentHover'; +import { ContentHoverController, ResizableContentHoverWidget } from 'vs/editor/contrib/hover/browser/contentHover'; import { MarginHoverWidget } from 'vs/editor/contrib/hover/browser/marginHover'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -28,7 +28,6 @@ import { MarkdownHoverParticipant } from 'vs/editor/contrib/hover/browser/markdo import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/browser/markerHoverParticipant'; import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineSuggestionHintsWidget'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ResizableContentHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; import * as nls from 'vs/nls'; import 'vs/css!./hover'; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 747d41ccaae43..a618b340c906c 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -140,10 +140,6 @@ export abstract class ResizableContentWidget implements IContentWidget { } getDomNode(): HTMLElement { - - console.log('Inside of getDomNode of ResizableContentWidget'); - console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); - return this.resizableWidget.element.domNode; } diff --git a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts b/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts deleted file mode 100644 index 419b608c60d64..0000000000000 --- a/src/vs/editor/contrib/hover/browser/resizableHoverWidget.ts +++ /dev/null @@ -1,593 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; -import * as dom from 'vs/base/browser/dom'; -import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; -import { Position } from 'vs/editor/common/core/position'; -import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { PositionAffinity } from 'vs/editor/common/model'; -import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; -import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; - -const SCROLLBAR_WIDTH = 10; - -// TODO: How to increase the z-index so that appears above the tabs? Somehow does not work - -export class ResizableHoverWidget extends ResizableWidget { - - private disposableStore = new DisposableStore(); - private resizableContentWidget: ResizableContentHoverWidget; - private visibleData: ContentHoverVisibleData | null = null; - private renderingAbove: ContentWidgetPositionPreference; - private visible: boolean = false; - - public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); - public readonly allowEditorOverflow = true; - - private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); - private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); - private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.getDomNode())); - private readonly horizontalScrollingBy: number = 30; - - constructor( - editor: ICodeEditor, - @IContextKeyService private readonly _contextKeyService: IContextKeyService - ) { - super(editor, new MultipleSizePersistingOptions()); - dom.append(this.element.domNode, this.hoverWidget.containerDomNode); - - this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); - this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - - this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); - this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { - if (e.hasChanged(EditorOption.fontInfo)) { - this._updateFont(); - } - })); - this.disposableStore.add(this.focusTracker.onDidFocus(() => { - this.hoverFocusedKey.set(true); - })); - this.disposableStore.add(this.focusTracker.onDidBlur(() => { - this.hoverFocusedKey.set(false); - })); - this._setVisibleData(null); - this._layout(); - } - - public get position(): Position | null { - return this.visibleData?.showAtPosition ?? null; - } - - public get isColorPickerVisible(): boolean { - return Boolean(this.visibleData?.colorPicker); - } - - public get isVisibleFromKeyboard(): boolean { - return (this.visibleData?.source === HoverStartSource.Keyboard); - } - - public get isVisible(): boolean { - return this.hoverVisibleKey.get() ?? false; - } - - public override resize(size: dom.Dimension) { - - console.log('Inside of resize'); - console.log('size : ', size); - - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - - // TODO: Change the pixel sizes - const width = size.width - 6 + 'px'; - this.hoverWidget.containerDomNode.style.width = width; - this.hoverWidget.contentsDomNode.style.width = width; - - // TODO: There are issues with this part - // const height = size.height - 6 + 'px'; - // this.hoverWidget.containerDomNode.style.height = height; - // this.hoverWidget.contentsDomNode.style.height = height; - - const horizontalSashLength = size.width - 4 + 'px'; - this.element.northSash.el.style.width = horizontalSashLength; - this.element.southSash.el.style.width = horizontalSashLength; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - const verticalSashLength = size.height - 4 + 'px'; - this.element.eastSash.el.style.height = verticalSashLength; - this.element.westSash.el.style.height = verticalSashLength; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; - - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - - if (hasHorizontalScrollbar) { - - console.log('has horizontal scrollbar in the resize function'); - - // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - } - this.hoverWidget.containerDomNode.style.height = size.height - 6 + 'px'; - this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 6 + 'px'; - } else { - - console.log('Does not have horizontal scrollbar in the resize function'); - // TODO: There is still an error, why does the size change before event resize is called? - this.hoverWidget.containerDomNode.style.height = size.height - 6 + 'px'; - this.hoverWidget.contentsDomNode.style.height = size.height - 6 + 'px'; - // this.hoverWidget.contentsDomNode.style.height = size.height + 'px'; - this.element.layout(size.height, size.width); - } - - // const maximumRenderingWidth = this.findMaximumRenderingWidth(); - // const maximumRenderingHeight = this.findMaximumRenderingHeight(); - // console.log('maximumRenderingWidth : ', maximumRenderingWidth); - // console.log('maximumRenderingHeight : ', maximumRenderingHeight); - // if (!maximumRenderingWidth || !maximumRenderingHeight) { - // return; - // } - // this.element.maxSize = new dom.Dimension(maximumRenderingWidth, maximumRenderingHeight); - - this.hoverWidget.scrollbar.scanDomNode(); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - - console.log('this.resizableWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); - } - - public findAvailableSpace(): number | undefined { - if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { - return; - } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); - const bodyBox = dom.getClientArea(document.body); - let availableSpace: number; - - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableSpace = editorBox.top + mouseBox.top - 30; - } else { - const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; - availableSpace = bodyBox.height - mouseBottom; - } - - return availableSpace; - } - - public override findMaximumRenderingHeight(): number | undefined { - - const availableSpace = this.findAvailableSpace(); - if (!availableSpace) { - return; - } - - let divMaxHeight = 7; - for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { - console.log('childHTMLElement : ', childHtmlElement); - console.log('childHTMLElement.innerHTML : ', childHtmlElement.innerHTML); - console.log('childHtmlElement.clientHeight : ', childHtmlElement.clientHeight); - divMaxHeight += childHtmlElement.clientHeight; - } - - if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { - - console.log('Adding the scrollbar width when there is a horizontal scrollbar'); - - divMaxHeight += SCROLLBAR_WIDTH; - } - - return Math.min(availableSpace, divMaxHeight); - } - - public override findMaximumRenderingWidth(): number | undefined { - if (!this.editor || !this.editor.hasModel()) { - return; - } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const widthOfEditor = editorBox.width; - const leftOfEditor = editorBox.left; - const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; - const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; - return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; - } - - public override dispose(): void { - this.editor.removeContentWidget(this.resizableContentWidget); - if (this.visibleData) { - this.visibleData.disposables.dispose(); - } - super.dispose(); - } - - public getDomNode() { - return this.hoverWidget.containerDomNode; - } - - public getContentsDomNode() { - return this.hoverWidget.contentsDomNode; - } - - public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this.visibleData) { - return false; - } - if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { - this.visibleData.initialMousePosX = posx; - this.visibleData.initialMousePosY = posy; - return false; - } - - const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); - if (typeof this.visibleData.closestMouseDistance === 'undefined') { - this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - } - const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { - // The mouse is getting farther away - return false; - } - this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); - return true; - } - - private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { - if (this.visibleData) { - this.visibleData.disposables.dispose(); - } - this.visibleData = visibleData; - this.hoverVisibleKey.set(!!this.visibleData); - this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); - } - - private _layout(): void { - const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); - - this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; - this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - } - - private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); - codeClasses.forEach(node => this.editor.applyFontInfo(node)); - } - - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - - console.log('Inside of showAt'); - - if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { - this.persistingMechanism.position = visibleData.showAtPosition; - } - this.resizableContentWidget.position = visibleData.showAtPosition; - this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; - this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - - const domNode = this.resizableContentWidget.getDomNode(); - domNode.style.position = 'fixed'; - domNode.style.zIndex = '50'; - - if (!this.visible) { - this.editor.addContentWidget(this.resizableContentWidget); - } - - const persistedSize = this.findPersistedSize(); - - if (!this.editor || !this.editor.hasModel()) { - return; - } - - this._setVisibleData(visibleData); - - this.hoverWidget.contentsDomNode.textContent = ''; - this.hoverWidget.contentsDomNode.appendChild(node); - this.hoverWidget.contentsDomNode.style.paddingBottom = ''; - this._updateFont(); - - let height; - // If the persisted size has already been found then set a maximum height and width - if (!persistedSize) { - this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - this.onContentsChanged(); - - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this.editor.render(); - height = domNode.clientHeight; - } - // When there is a persisted size then do not use a maximum height or width - else { - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - height = persistedSize.height; - } - - // The dimensions of the document in which we are displaying the hover - const bodyBox = dom.getClientArea(document.body); - // Hard-coded in the hover.css file as 1.5em or 24px - const minHeight = 24; - // The full height is already passed in as a parameter - const fullHeight = height; - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); - // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height - const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position - const availableSpaceBelow = bodyBox.height - mouseBottom; - // Max height below is the minimum of the available space below and the full height of the widget - const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); - // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor - const availableSpaceAbove = editorBox.top + mouseBox.top - 30; - const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); - // We find the maximum height of the widget possible on the top or on the bottom - const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); - - if (height < minHeight) { - height = minHeight; - } - if (height > maxHeight) { - height = maxHeight; - } - - // Determining whether we should render above or not ideally - if (this.editor.getOption(EditorOption.hover).above) { - this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - } else { - this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; - } - - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { - this.element.enableSashes(true, true, false, false); - } else { - this.element.enableSashes(false, true, true, false); - } - - this.resizableContentWidget.preference = [this.renderingAbove]; - - // See https://github.com/microsoft/vscode/issues/140339 - // TODO: Doing a second layout of the hover after force rendering the editor - if (!persistedSize) { - this.onContentsChanged(); - } - - if (visibleData.stoleFocus) { - this.hoverWidget.containerDomNode.focus(); - } - visibleData.colorPicker?.layout(); - - if (!this.visibleData) { - return; - } - - this.visible = true; - } - - public override hide(): void { - - console.log('Inside of hide of ResizableHoverWidget'); - this.visible = false; - this.element.maxSize = new dom.Dimension(Infinity, Infinity); - this.element.clearSashHoverState(); - this.editor.removeContentWidget(this.resizableContentWidget); - if (this.visibleData) { - const stoleFocus = this.visibleData.stoleFocus; - this._setVisibleData(null); - this.editor.layoutContentWidget(this.resizableContentWidget); - if (stoleFocus) { - this.editor.focus(); - } - } - } - - public onContentsChanged(): void { - - console.log('Inside of onContentsChanged'); - - const persistedSize = this.resizableContentWidget.findPersistedSize(); - const containerDomNode = this.getDomNode(); - const contentsDomNode = this.getContentsDomNode(); - - // Suppose a persisted size is defined - if (persistedSize) { - - console.log('Using persisted size'); - console.log('persistedSize.height: ' + persistedSize.height); - console.log('persistedSize.width: ' + persistedSize.width); - - console.log('this.findMaximumRenderingWidth() : ', this.findMaximumRenderingWidth()); - console.log('this.findMaximumRenderingHeight() : ', this.findMaximumRenderingHeight()); - - const width = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width - 6); - const height = Math.min(this.findAvailableSpace() ?? Infinity, persistedSize.height - 6); - - console.log('width : ', width); - console.log('height : ', height); - - containerDomNode.style.width = width + 'px'; - containerDomNode.style.height = height + 'px'; - contentsDomNode.style.width = width + 'px'; - contentsDomNode.style.height = height + 'px'; - - this.element.layout(persistedSize.height, persistedSize.width); - - } else { - - console.log('Not using persisted size'); - - containerDomNode.style.width = 'auto'; - containerDomNode.style.height = 'auto'; - contentsDomNode.style.width = 'auto'; - contentsDomNode.style.height = 'auto'; - } - - this.editor.layoutContentWidget(this.resizableContentWidget); - this.hoverWidget.onContentsChanged(); - - const clientHeight = containerDomNode.clientHeight; - const clientWidth = containerDomNode.clientWidth; - - this.element.layout(clientHeight + 6, clientWidth + 6); - containerDomNode.style.height = clientHeight + 'px'; - containerDomNode.style.width = clientWidth + 'px'; - containerDomNode.style.top = 2 + 'px'; - containerDomNode.style.left = 2 + 'px'; - - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - - if (hasHorizontalScrollbar) { - console.log('has horizontal scrollbar'); - - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - } - const maxRenderingHeight = this.findMaximumRenderingHeight(); - - if (!maxRenderingHeight) { - return; - } - - if (persistedSize) { - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6 - SCROLLBAR_WIDTH) + 'px'; - } else { - containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; - } - this.element.layout(clientHeight + 6, clientWidth + 6); - this.editor.layoutContentWidget(this.resizableContentWidget); - this.hoverWidget.onContentsChanged(); - } - - console.log('Before changing the sash size'); - - const finalClientHeight = containerDomNode.clientHeight + 2; - const finalClientWidth = containerDomNode.clientWidth + 2; - - this.element.northSash.el.style.width = finalClientWidth + 'px'; - this.element.southSash.el.style.width = finalClientWidth + 'px'; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - - this.element.eastSash.el.style.height = finalClientHeight + 'px'; - this.element.westSash.el.style.height = finalClientHeight + 'px'; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; - - this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - } - - public clear(): void { - this.hoverWidget.contentsDomNode.textContent = ''; - } - - public focus(): void { - this.hoverWidget.containerDomNode.focus(); - } - - public scrollUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); - } - - public scrollDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); - } - - public scrollLeft(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); - } - - public scrollRight(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); - } - - public pageUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); - } - - public pageDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); - } - - public goToTop(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); - } - - public goToBottom(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); - } - - public escape(): void { - this.editor.focus(); - } - - public clearPersistedSizes(): void { - this.persistingMechanism.clear(); - } -} - -export class ResizableContentHoverWidget extends ResizableContentWidget { - - public static ID = 'editor.contrib.resizableContentHoverWidget'; - - constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { - super(resizableHoverWidget, editor); - } - - public getId(): string { - return ResizableContentHoverWidget.ID; - } -} - -class ContentHoverVisibleData { - - public closestMouseDistance: number | undefined = undefined; - - constructor( - public readonly colorPicker: IEditorHoverColorPickerWidget | null, - public readonly showAtPosition: Position, - public readonly showAtSecondaryPosition: Position, - public readonly preferAbove: boolean, - public readonly stoleFocus: boolean, - public readonly source: HoverStartSource, - public readonly isBeforeContent: boolean, - public initialMousePosX: number | undefined, - public initialMousePosY: number | undefined, - public readonly disposables: DisposableStore - ) { } -} - -function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { - const x = (left + width / 2); // x center of rectangle - const y = (top + height / 2); // y center of rectangle - const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); - const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); - return Math.sqrt(dx * dx + dy * dy); -} From 4cdf211f3a2a36ef5395e9d2ce9a24a695796c6a Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 16:09:14 +0200 Subject: [PATCH 37/72] adding two to the client height and client width after the layout in order for everything to render correctly --- src/vs/editor/contrib/hover/browser/contentHover.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 011047bcccaba..65f5f7253e400 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -850,7 +850,7 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; - // --- + // Added because otherwise the initial size of the hover content is not the initial one this.element.domNode.style.width = 100000 + 'px'; this.element.domNode.style.height = 100000 + 'px'; } @@ -884,11 +884,16 @@ export class ResizableHoverWidget extends ResizableWidget { console.log('resizableClientHeight', resizableClientHeight); console.log('resizableClientWidth : ', resizableClientWidth); + containerDomNode.style.height = clientHeight + 2 + 'px'; + containerDomNode.style.width = clientWidth + 2 + 'px'; + + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + this.element.layout(clientHeight + 6, clientWidth + 6); - // --- this.element.domNode.style.width = clientWidth + 6 + 'px'; this.element.domNode.style.height = clientHeight + 6 + 'px'; - // --- + containerDomNode.style.height = clientHeight + 'px'; containerDomNode.style.width = clientWidth + 'px'; containerDomNode.style.top = 2 + 'px'; From 21b6dfcec7a9e5f196005aaaa42b66eb822df4fe Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 16:15:42 +0200 Subject: [PATCH 38/72] using different code when persisting the size and when not --- .../contrib/hover/browser/contentHover.ts | 88 +++++++++++++------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 65f5f7253e400..0190112f499ec 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -842,6 +842,36 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.width = width + 'px'; contentsDomNode.style.height = height + 'px'; // this.element.layout(persistedSize.height, persistedSize.width); + + console.log('Before layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + + this.editor.layoutContentWidget(this.resizableContentWidget); + this.hoverWidget.onContentsChanged(); + + console.log('After layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + } else { console.log('Not using persisted size'); @@ -853,39 +883,41 @@ export class ResizableHoverWidget extends ResizableWidget { // Added because otherwise the initial size of the hover content is not the initial one this.element.domNode.style.width = 100000 + 'px'; this.element.domNode.style.height = 100000 + 'px'; - } - console.log('Before layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); + // --- - this.editor.layoutContentWidget(this.resizableContentWidget); - this.hoverWidget.onContentsChanged(); + console.log('Before layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; - console.log('After layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); + this.editor.layoutContentWidget(this.resizableContentWidget); + this.hoverWidget.onContentsChanged(); - containerDomNode.style.height = clientHeight + 2 + 'px'; - containerDomNode.style.width = clientWidth + 2 + 'px'; + console.log('After layoutContentWidget'); + clientHeight = containerDomNode.clientHeight; + clientWidth = containerDomNode.clientWidth; + resizableClientHeight = resizableContentDomNode.clientHeight; + resizableClientWidth = resizableContentDomNode.clientWidth; + + console.log('containerDomNode : ', containerDomNode); + console.log('contentsDomNode : ', contentsDomNode); + console.log('clientHeight', clientHeight); + console.log('clientWidth : ', clientWidth); + console.log('resizableClientHeight', resizableClientHeight); + console.log('resizableClientWidth : ', resizableClientWidth); + + containerDomNode.style.height = clientHeight + 2 + 'px'; + containerDomNode.style.width = clientWidth + 2 + 'px'; + } clientHeight = containerDomNode.clientHeight; clientWidth = containerDomNode.clientWidth; From 1840cc553e1e8ed4c3bea943c61b53e6a0efff05 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 17:01:20 +0200 Subject: [PATCH 39/72] cleaning the code --- src/vs/base/browser/ui/sash/sash.css | 2 +- .../contrib/hover/browser/contentHover.ts | 190 +++--------------- src/vs/editor/contrib/hover/browser/hover.ts | 1 - .../hover/browser/resizableContentWidget.ts | 35 +--- 4 files changed, 31 insertions(+), 197 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.css b/src/vs/base/browser/ui/sash/sash.css index 40bd11fe8017d..fdcbc26609e07 100644 --- a/src/vs/base/browser/ui/sash/sash.css +++ b/src/vs/base/browser/ui/sash/sash.css @@ -107,7 +107,7 @@ position: absolute; width: 100%; height: 100%; - background: red; + background: transparent; } .monaco-workbench:not(.reduce-motion) .monaco-sash:before { diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 0190112f499ec..ee7ed73122a11 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -539,11 +539,13 @@ export class ResizableHoverWidget extends ResizableWidget { if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - this.hoverWidget.containerDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.hoverWidget.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this.hoverWidget.containerDomNode.style.height = height + 'px'; + this.hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; } else { - this.hoverWidget.containerDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.hoverWidget.contentsDomNode.style.height = size.height - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this.hoverWidget.containerDomNode.style.height = height + 'px'; + this.hoverWidget.contentsDomNode.style.height = height + 'px'; } this.hoverWidget.scrollbar.scanDomNode(); @@ -579,20 +581,16 @@ export class ResizableHoverWidget extends ResizableWidget { if (!availableSpace) { return; } - - let divMaxHeight = 2 * SASH_WIDTH_MINUS_BORDER + 1; + let divMaxHeight = 3 * SASH_WIDTH_MINUS_BORDER; for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } - if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { divMaxHeight += SCROLLBAR_WIDTH; } - return Math.min(availableSpace, divMaxHeight); } - // Here findMaximumRenderingWidth and findAvailableSpaceHorizontally are the same public override findMaximumRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; @@ -670,43 +668,21 @@ export class ResizableHoverWidget extends ResizableWidget { public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - console.log('Inside of showAt'); - - let clientHeight; - let clientWidth; - const containerDomNode = this.getDomNode(); - if (!this.editor || !this.editor.hasModel()) { return; } - if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { this.persistingMechanism.position = visibleData.showAtPosition; } this.resizableContentWidget.position = visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - // const resizableContent = this.resizableContentWidget.getDomNode(); - // resizableContent.style.width = 'auto'; - // resizableContent.style.height = 'auto'; this._setVisibleData(visibleData); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - console.log('Before adding content widget'); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - if (!this.visible) { this.editor.addContentWidget(this.resizableContentWidget); } - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - console.log('After adding content widget'); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - const persistedSize = this.findPersistedSize(); this.hoverWidget.contentsDomNode.textContent = ''; this.hoverWidget.contentsDomNode.appendChild(node); @@ -714,15 +690,10 @@ export class ResizableHoverWidget extends ResizableWidget { this._updateFont(); let height; - - // If there is no persisted size, then do normal rendering + // If there is no persisted size, then normally render if (!persistedSize) { this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - - // this.hoverWidget.containerDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - // this.hoverWidget.containerDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - this.onContentsChanged(); // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' @@ -808,30 +779,9 @@ export class ResizableHoverWidget extends ResizableWidget { public onContentsChanged(): void { - let clientHeight; - let clientWidth; - let resizableClientHeight; - let resizableClientWidth; - - console.log('inside of on contents changed'); - console.log('this.resizableContentWidget.getDomNode() : ', this.resizableContentWidget.getDomNode()); - const persistedSize = this.resizableContentWidget.findPersistedSize(); - // const resizableContent = this.resizableContentWidget.getDomNode(); const containerDomNode = this.getDomNode(); const contentsDomNode = this.getContentsDomNode(); - const resizableContentDomNode = this.resizableContentWidget.getDomNode(); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); // Suppose a persisted size is defined if (persistedSize) { @@ -841,154 +791,72 @@ export class ResizableHoverWidget extends ResizableWidget { containerDomNode.style.height = height + 'px'; contentsDomNode.style.width = width + 'px'; contentsDomNode.style.height = height + 'px'; - // this.element.layout(persistedSize.height, persistedSize.width); - - console.log('Before layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); - this.editor.layoutContentWidget(this.resizableContentWidget); this.hoverWidget.onContentsChanged(); - console.log('After layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); - } else { - console.log('Not using persisted size'); containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; - - // Added because otherwise the initial size of the hover content is not the initial one - this.element.domNode.style.width = 100000 + 'px'; - this.element.domNode.style.height = 100000 + 'px'; - - // --- - - console.log('Before layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); - + // Added because otherwise the initial size of the hover content is smaller than should be + this.element.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; + this.element.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; this.editor.layoutContentWidget(this.resizableContentWidget); this.hoverWidget.onContentsChanged(); - - console.log('After layoutContentWidget'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); - - containerDomNode.style.height = clientHeight + 2 + 'px'; - containerDomNode.style.width = clientWidth + 2 + 'px'; + containerDomNode.style.width = containerDomNode.clientWidth + 2 + 'px'; } - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; + const clientHeight = containerDomNode.clientHeight; + const clientWidth = containerDomNode.clientWidth; - this.element.layout(clientHeight + 6, clientWidth + 6); - this.element.domNode.style.width = clientWidth + 6 + 'px'; - this.element.domNode.style.height = clientHeight + 6 + 'px'; + this.element.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); + this.element.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.element.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; containerDomNode.style.height = clientHeight + 'px'; containerDomNode.style.width = clientWidth + 'px'; - containerDomNode.style.top = 2 + 'px'; - containerDomNode.style.left = 2 + 'px'; + containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { - console.log('has horizontal scrollbar'); - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } const maxRenderingHeight = this.findMaximumRenderingHeight(); - if (!maxRenderingHeight) { return; } - if (persistedSize) { - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - 6 - SCROLLBAR_WIDTH) + 'px'; + const persistedHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight - SCROLLBAR_WIDTH) + 'px'; } else { containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; } - this.element.layout(clientHeight + 6, clientWidth + 6); - this.editor.layoutContentWidget(this.resizableContentWidget); + this.element.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); this.hoverWidget.onContentsChanged(); } - console.log('Before changing the sash size'); - - const finalClientHeight = containerDomNode.clientHeight + 2; - const finalClientWidth = containerDomNode.clientWidth + 2; + const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; + const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; - this.element.northSash.el.style.width = finalClientWidth + 'px'; - this.element.southSash.el.style.width = finalClientWidth + 'px'; + this.element.northSash.el.style.width = horizontalSashLength + 'px'; + this.element.southSash.el.style.width = horizontalSashLength + 'px'; this.element.northSash.el.style.left = 2 + 'px'; this.element.southSash.el.style.left = 2 + 'px'; - this.element.eastSash.el.style.height = finalClientHeight + 'px'; - this.element.westSash.el.style.height = finalClientHeight + 'px'; + this.element.eastSash.el.style.height = verticalSashLength + 'px'; + this.element.westSash.el.style.height = verticalSashLength + 'px'; this.element.eastSash.el.style.top = 2 + 'px'; this.element.westSash.el.style.top = 2 + 'px'; this.editor.layoutContentWidget(this.resizableContentWidget); - this.editor.render(); - - console.log('At the end of on contents changed'); - clientHeight = containerDomNode.clientHeight; - clientWidth = containerDomNode.clientWidth; - resizableClientHeight = resizableContentDomNode.clientHeight; - resizableClientWidth = resizableContentDomNode.clientWidth; - - console.log('containerDomNode : ', containerDomNode); - console.log('contentsDomNode : ', contentsDomNode); - console.log('clientHeight', clientHeight); - console.log('clientWidth : ', clientWidth); - console.log('resizableClientHeight', resizableClientHeight); - console.log('resizableClientWidth : ', resizableClientWidth); } public clear(): void { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index ee5e73f00e242..57b3d532324c2 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -139,7 +139,6 @@ export class ModesHoverController implements IEditorContribution { } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { - // console.log('mouseEvent : ', mouseEvent); const target = mouseEvent.target; if (this._isMouseDown && this._hoverClicked) { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index a618b340c906c..95864b99a5e4c 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -47,8 +47,6 @@ export abstract class ResizableWidget implements IResizableWidget { private readonly persistingOptions: IPersistingOptions, ) { - console.log('Inside of ResizableWidget constructor'); - this.element = this.disposables.add(new ResizableHTMLElement()); this.element.minSize = new dom.Dimension(10, 24); @@ -129,9 +127,7 @@ export abstract class ResizableContentWidget implements IContentWidget { constructor( private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor - ) { - console.log('Inside of ResizableContentWidget constructor'); - } + ) { } abstract getId(): string; @@ -144,25 +140,16 @@ export abstract class ResizableContentWidget implements IContentWidget { } 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 { - - console.log('Inside of hide of the ResizableContentWidget'); - this.editor.removeContentWidget(this); } @@ -270,9 +257,6 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly resizableWidget: ResizableWidget, public readonly editor: ICodeEditor ) { - - console.log('Inside of constructor of the multiple size persisting mechanism'); - this.disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; if (!uri || !this.persistedWidgetSizes.has(uri)) { @@ -303,29 +287,15 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { this.disposables.add(this.resizableWidget.element.onDidResize(e => { - console.log('Inside of on did resize of the multiple size persisting mechanism'); - console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); - console.log('e : ', e); - const height = e.dimension.height; const width = e.dimension.width; - this.resizableWidget.resize(new dom.Dimension(width, height)); - - console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); - const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); - - console.log('maxRenderingWidth : ', maxRenderingWidth); - console.log('maxRenderingHeight : ', maxRenderingHeight); - if (!maxRenderingWidth || !maxRenderingHeight) { return; } - this.resizableWidget.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); - if (e.done) { if (!this.editor.hasModel()) { return; @@ -359,9 +329,6 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } findSize(): dom.Dimension | undefined { - - console.log('Inside of findSize of the MultiplePersistingMechanisms'); - if (!this._position || !this.editor.hasModel()) { return; } From a138a4927afa170e632757e54ed995ae6ab820f7 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 17:54:57 +0200 Subject: [PATCH 40/72] Cleaning the code --- .../contrib/hover/browser/contentHover.ts | 79 +++++----- .../hover/browser/resizableContentWidget.ts | 147 +++++++++++++----- 2 files changed, 143 insertions(+), 83 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index ee7ed73122a11..cf9ed919edf18 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -457,14 +457,14 @@ export class ResizableHoverWidget extends ResizableWidget { private disposableStore = new DisposableStore(); private resizableContentWidget: ResizableContentHoverWidget; private visibleData: ContentHoverVisibleData | null = null; - private renderingAbove: ContentWidgetPositionPreference; + private renderingAbove: ContentWidgetPositionPreference | null = null; private visible: boolean = false; - public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); public readonly allowEditorOverflow = true; + public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); - private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.getDomNode())); + private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); private readonly horizontalScrollingBy: number = 30; constructor( @@ -477,7 +477,6 @@ export class ResizableHoverWidget extends ResizableWidget { dom.append(this.element.domNode, this.hoverWidget.containerDomNode); this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); - this.renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { @@ -515,17 +514,6 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - this.element.northSash.el.style.width = horizontalSashLength; - this.element.southSash.el.style.width = horizontalSashLength; - this.element.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - this.element.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - this.element.eastSash.el.style.height = verticalSashLength; - this.element.westSash.el.style.height = verticalSashLength; - this.element.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - this.element.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; @@ -548,6 +536,17 @@ export class ResizableHoverWidget extends ResizableWidget { this.hoverWidget.contentsDomNode.style.height = height + 'px'; } + const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; + this.element.northSash.el.style.width = horizontalSashLength; + this.element.southSash.el.style.width = horizontalSashLength; + this.element.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this.element.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; + this.element.eastSash.el.style.height = verticalSashLength; + this.element.westSash.el.style.height = verticalSashLength; + this.element.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.element.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); } @@ -615,10 +614,6 @@ export class ResizableHoverWidget extends ResizableWidget { return this.hoverWidget.containerDomNode; } - public getContentsDomNode() { - return this.hoverWidget.contentsDomNode; - } - public isMouseGettingCloser(posx: number, posy: number): boolean { if (!this.visibleData) { return false; @@ -683,13 +678,13 @@ export class ResizableHoverWidget extends ResizableWidget { this.editor.addContentWidget(this.resizableContentWidget); } - const persistedSize = this.findPersistedSize(); this.hoverWidget.contentsDomNode.textContent = ''; this.hoverWidget.contentsDomNode.appendChild(node); this.hoverWidget.contentsDomNode.style.paddingBottom = ''; this._updateFont(); let height; + const persistedSize = this.findPersistedSize(); // If there is no persisted size, then normally render if (!persistedSize) { this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; @@ -777,25 +772,27 @@ export class ResizableHoverWidget extends ResizableWidget { } } + private _layoutContentWidget(): void { + this.editor.layoutContentWidget(this.resizableContentWidget); + this.hoverWidget.onContentsChanged(); + } + public onContentsChanged(): void { - const persistedSize = this.resizableContentWidget.findPersistedSize(); - const containerDomNode = this.getDomNode(); - const contentsDomNode = this.getContentsDomNode(); + const persistedSize = this.findPersistedSize(); + const containerDomNode = this.hoverWidget.containerDomNode; + const contentsDomNode = this.hoverWidget.contentsDomNode; // Suppose a persisted size is defined if (persistedSize) { - const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 6); - const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 6); + const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); + const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); containerDomNode.style.width = width + 'px'; containerDomNode.style.height = height + 'px'; contentsDomNode.style.width = width + 'px'; contentsDomNode.style.height = height + 'px'; - this.editor.layoutContentWidget(this.resizableContentWidget); - this.hoverWidget.onContentsChanged(); - + this._layoutContentWidget(); } else { - containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; contentsDomNode.style.width = 'auto'; @@ -803,9 +800,9 @@ export class ResizableHoverWidget extends ResizableWidget { // Added because otherwise the initial size of the hover content is smaller than should be this.element.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; this.element.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; - this.editor.layoutContentWidget(this.resizableContentWidget); - this.hoverWidget.onContentsChanged(); - containerDomNode.style.width = containerDomNode.clientWidth + 2 + 'px'; + this._layoutContentWidget(); + // Added otherwise rendered too small horizontally + containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; } const clientHeight = containerDomNode.clientHeight; @@ -815,8 +812,6 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; this.element.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - containerDomNode.style.height = clientHeight + 'px'; - containerDomNode.style.width = clientWidth + 'px'; containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; @@ -839,8 +834,6 @@ export class ResizableHoverWidget extends ResizableWidget { containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; } - this.element.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this.hoverWidget.onContentsChanged(); } const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; @@ -848,15 +841,13 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.northSash.el.style.width = horizontalSashLength + 'px'; this.element.southSash.el.style.width = horizontalSashLength + 'px'; - this.element.northSash.el.style.left = 2 + 'px'; - this.element.southSash.el.style.left = 2 + 'px'; - + this.element.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.element.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; this.element.eastSash.el.style.height = verticalSashLength + 'px'; this.element.westSash.el.style.height = verticalSashLength + 'px'; - this.element.eastSash.el.style.top = 2 + 'px'; - this.element.westSash.el.style.top = 2 + 'px'; - - this.editor.layoutContentWidget(this.resizableContentWidget); + this.element.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.element.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._layoutContentWidget(); } public clear(): void { @@ -923,7 +914,7 @@ export class ResizableContentHoverWidget extends ResizableContentWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { - super(resizableHoverWidget, editor); + super(resizableHoverWidget); } public getId(): string { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 95864b99a5e4c..1d31cbae4cb90 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -16,22 +16,45 @@ import * as dom from 'vs/base/browser/dom'; export interface IResizableWidget extends IDisposable { + /** + * This method returns a boolean indicating whether the widget is currently resizing. + */ isResizing(): boolean; + /** + * Abstract method called when the resizable element is resizing. Should be used to define the new size of the children of the resizable element. + * @param dimension The new dimension of the resizable element. + */ resize(dimension: dom.Dimension): void; - hide(): void; - + /** + * Method which should return the maximum current rendering height. By default is returns infinity. + */ findMaximumRenderingHeight(): number | undefined; + /** + * Method which should return the maximum current rendering width. By default is returns infinity. + */ findMaximumRenderingWidth(): number | undefined; + /** + * Method which returns the persisted size the resizable widget. It calls the findSize method of the persisting mechanism (whether single or multiple size persisting mechanism). + */ findPersistedSize(): dom.Dimension | undefined; + /** + * Method which is called first in the onDidWillResize call of the resizable element. By default it returns nothing. + */ beforeOnDidWillResize(): void; + /** + * Method which is called last in the onDidResize call of the resizable element. By default it returns nothing. + */ afterOnDidResize(): void; + /** + * Method which disposes the resizable widget. + */ dispose(): void; } @@ -68,21 +91,12 @@ export abstract class ResizableWidget implements IResizableWidget { })); } + abstract resize(dimension: dom.Dimension): void; + isResizing() { return this.resizing; } - dispose(): void { - this.disposables.dispose(); - } - - resize(dimension: dom.Dimension): void { } - - hide(): void { - this.resizing = false; - this.element.clearSashHoverState(); - } - findMaximumRenderingHeight(): number | undefined { return Infinity; } @@ -102,22 +116,51 @@ export abstract class ResizableWidget implements IResizableWidget { afterOnDidResize() { return; } -} -export interface IResizableContentWidget { + dispose(): void { + this.disposables.dispose(); + } +} - findPersistedSize(): dom.Dimension | undefined; +export interface IResizableContentWidget extends IContentWidget { + /** + * Abstract method which returns the ID of the content widget + */ getId(): string; + /** + * Method which returns the dom node of the resizable element of the resizable widget passed into the constructor + */ getDomNode(): HTMLElement; + /** + * Returns the position of the content widget. + */ getPosition(): IContentWidgetPosition | null; - hide(): void; + /** + * Method which sets the position of the content widget. + */ + set position(position: IPosition | null); + + /** + * Method which sets the secondary position of the content widget. + */ + set secondaryPosition(position: IPosition | null); + + /** + * Method which sets the preferred position of the content widget. + */ + set preference(preference: ContentWidgetPositionPreference[]); + + /** + * Method which sets the position affinity of the content widget. + */ + set positionAffinity(affinity: PositionAffinity | undefined); } -export abstract class ResizableContentWidget implements IContentWidget { +export abstract class ResizableContentWidget implements IResizableContentWidget { private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; @@ -125,16 +168,12 @@ export abstract class ResizableContentWidget implements IContentWidget { private _positionAffinity: PositionAffinity | undefined = undefined; constructor( - private readonly resizableWidget: ResizableWidget, - private readonly editor: ICodeEditor + private readonly resizableWidget: ResizableWidget ) { } + // Method is to abstract because generally we return a static ID abstract getId(): string; - findPersistedSize(): dom.Dimension | undefined { - return this.resizableWidget.findPersistedSize(); - } - getDomNode(): HTMLElement { return this.resizableWidget.element.domNode; } @@ -149,10 +188,6 @@ export abstract class ResizableContentWidget implements IContentWidget { return contentWidgetPosition; } - hide(): void { - this.editor.removeContentWidget(this); - } - set position(position: IPosition | null) { this._position = position; } @@ -185,10 +220,26 @@ export class MultipleSizePersistingOptions implements IPersistingOptions { } interface IPersistingMechanism extends IDisposable { + + /** + * Method which returns the current appropriate persisted size of the widget. + */ findSize(): dom.Dimension | undefined; + + /** + * Method which clears the persisted size(s) of the widget. + */ clear(): void; + + /** + * Method which disposes the persisting mechanism. + */ + dispose(): void; } +/** + * Class which can be used to define a mechanism that persists the size of a resizable widget. The persisted size is stored using the storage service. + */ export class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly persistedWidgetSize: PersistedWidgetSize | null = null; @@ -209,6 +260,12 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { })); this.disposables.add(this.resizableWidget.element.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); + const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); + const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); + if (!maxRenderingWidth || !maxRenderingHeight) { + return; + } + this.resizableWidget.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; state.persistWidth = state.persistWidth || !!e.east || !!e.west; @@ -229,8 +286,8 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { } this.persistedWidgetSize!.store(new dom.Dimension(width, height)); } - this.resizableWidget.afterOnDidResize(); state = undefined; + this.resizableWidget.afterOnDidResize(); })); } @@ -238,15 +295,19 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { return this.persistedWidgetSize?.restore(); } - dispose(): void { - this.disposables.dispose(); - } - clear(): void { this.persistedWidgetSize?.reset(); } + + dispose(): void { + this.disposables.dispose(); + } } +/** + * Class which can be used to define a mechanism which persists the sizes of a resizable widget on a per token-basis. + * The sizes are saved in a ResourceMap which maps the document URI to the token position and its dom.Dimension persisted size. + */ export class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); @@ -284,9 +345,10 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } this.persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); - + this.disposables.add(this.resizableWidget.element.onDidWillResize(() => { + this.resizableWidget.beforeOnDidWillResize(); + })); this.disposables.add(this.resizableWidget.element.onDidResize(e => { - const height = e.dimension.height; const width = e.dimension.width; this.resizableWidget.resize(new dom.Dimension(width, height)); @@ -321,6 +383,7 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } } + this.resizableWidget.afterOnDidResize(); })); } @@ -346,15 +409,18 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { return persistedSizesForUri.get(JSON.stringify([offset, length])); } - dispose(): void { - this.disposables.dispose(); - } - clear(): void { this.persistedWidgetSizes.clear(); } + + dispose(): void { + this.disposables.dispose(); + } } +/** + * Class which is used in the single size persisting mechanism for resizable widgets. + */ class PersistedWidgetSize { constructor( @@ -384,6 +450,9 @@ class PersistedWidgetSize { } } +/** + * Class which is used in the single size persisting mechanism for resizable widgets. + */ class ResizeState { constructor( readonly persistedSize: dom.Dimension | undefined, From ab3ca52f53a11dfb3e90bbfa099dcdfac760826c Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 17:58:11 +0200 Subject: [PATCH 41/72] cleaning the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index cf9ed919edf18..cf1849c1a7050 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -662,7 +662,6 @@ export class ResizableHoverWidget extends ResizableWidget { } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - if (!this.editor || !this.editor.hasModel()) { return; } @@ -757,7 +756,7 @@ export class ResizableHoverWidget extends ResizableWidget { this.visible = true; } - public override hide(): void { + public hide(): void { this.visible = false; this.element.maxSize = new dom.Dimension(Infinity, Infinity); this.element.clearSashHoverState(); From 5a0c0bf04d8f2929b2e0a366ac6644ed485408a8 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 18:19:23 +0200 Subject: [PATCH 42/72] cleaing the code --- .../contrib/hover/browser/contentHover.ts | 13 +++++--- .../hover/browser/resizableContentWidget.ts | 30 ------------------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index cf1849c1a7050..f1558aeeb9778 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -509,7 +509,7 @@ export class ResizableHoverWidget extends ResizableWidget { return this.hoverVisibleKey.get() ?? false; } - public override resize(size: dom.Dimension) { + public resize(size: dom.Dimension) { this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; @@ -547,6 +547,12 @@ export class ResizableHoverWidget extends ResizableWidget { this.element.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; this.element.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + const maxRenderingWidth = this.findMaximumRenderingWidth(); + const maxRenderingHeight = this.findMaximumRenderingHeight(); + if (!maxRenderingWidth || !maxRenderingHeight) { + return; + } + this.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); this.hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); } @@ -574,7 +580,7 @@ export class ResizableHoverWidget extends ResizableWidget { return this.findMaximumRenderingWidth(); } - public override findMaximumRenderingHeight(): number | undefined { + public findMaximumRenderingHeight(): number | undefined { const availableSpace = this.findAvailableSpaceVertically(); if (!availableSpace) { @@ -590,7 +596,7 @@ export class ResizableHoverWidget extends ResizableWidget { return Math.min(availableSpace, divMaxHeight); } - public override findMaximumRenderingWidth(): number | undefined { + public findMaximumRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; } @@ -777,7 +783,6 @@ export class ResizableHoverWidget extends ResizableWidget { } public onContentsChanged(): void { - const persistedSize = this.findPersistedSize(); const containerDomNode = this.hoverWidget.containerDomNode; const contentsDomNode = this.hoverWidget.contentsDomNode; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 1d31cbae4cb90..5187e87855660 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -27,16 +27,6 @@ export interface IResizableWidget extends IDisposable { */ resize(dimension: dom.Dimension): void; - /** - * Method which should return the maximum current rendering height. By default is returns infinity. - */ - findMaximumRenderingHeight(): number | undefined; - - /** - * Method which should return the maximum current rendering width. By default is returns infinity. - */ - findMaximumRenderingWidth(): number | undefined; - /** * Method which returns the persisted size the resizable widget. It calls the findSize method of the persisting mechanism (whether single or multiple size persisting mechanism). */ @@ -97,14 +87,6 @@ export abstract class ResizableWidget implements IResizableWidget { return this.resizing; } - findMaximumRenderingHeight(): number | undefined { - return Infinity; - } - - findMaximumRenderingWidth(): number | undefined { - return Infinity; - } - findPersistedSize(): dom.Dimension | undefined { return this.persistingMechanism.findSize(); } @@ -260,12 +242,6 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { })); this.disposables.add(this.resizableWidget.element.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); - const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); - const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); - if (!maxRenderingWidth || !maxRenderingHeight) { - return; - } - this.resizableWidget.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; state.persistWidth = state.persistWidth || !!e.east || !!e.west; @@ -352,12 +328,6 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { const height = e.dimension.height; const width = e.dimension.width; this.resizableWidget.resize(new dom.Dimension(width, height)); - const maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); - const maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); - if (!maxRenderingWidth || !maxRenderingHeight) { - return; - } - this.resizableWidget.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); if (e.done) { if (!this.editor.hasModel()) { return; From 3b51b779929d318619ff9b7c64fb5dcbc495e832 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 5 Apr 2023 19:33:02 +0200 Subject: [PATCH 43/72] placing the hover widget into the resizable content hover widget --- .../editor/contrib/hover/browser/contentHover.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index f1558aeeb9778..9702efbcfbcea 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -456,15 +456,15 @@ export class ResizableHoverWidget extends ResizableWidget { private disposableStore = new DisposableStore(); private resizableContentWidget: ResizableContentHoverWidget; + private hoverWidget: HoverWidget; private visibleData: ContentHoverVisibleData | null = null; private renderingAbove: ContentWidgetPositionPreference | null = null; private visible: boolean = false; public readonly allowEditorOverflow = true; - public readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); - private readonly focusTracker: dom.IFocusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); + private readonly focusTracker: dom.IFocusTracker; private readonly horizontalScrollingBy: number = 30; constructor( @@ -474,9 +474,11 @@ export class ResizableHoverWidget extends ResizableWidget { super(editor, new MultipleSizePersistingOptions()); this.element.domNode.style.position = 'absolute'; this.element.domNode.style.zIndex = '50'; - dom.append(this.element.domNode, this.hoverWidget.containerDomNode); this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); + this.hoverWidget = this.resizableContentWidget.hoverWidget; + this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); + this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { @@ -915,15 +917,22 @@ export class ResizableHoverWidget extends ResizableWidget { export class ResizableContentHoverWidget extends ResizableContentWidget { + private _disposableStore = new DisposableStore(); + private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); public static ID = 'editor.contrib.resizableContentHoverWidget'; constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget); + dom.append(resizableHoverWidget.element.domNode, this._hoverWidget.containerDomNode); } public getId(): string { return ResizableContentHoverWidget.ID; } + + get hoverWidget() { + return this._hoverWidget; + } } class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { From 88d75f10651da8b8ec8103bf8e03e00f9cadc7b3 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 11 Apr 2023 17:54:49 +0200 Subject: [PATCH 44/72] adding code inspired from the review for a complete resizable widget --- .../contrib/hover/browser/contentHover.ts | 5 + .../browser/exampleResizableContentWidget.ts | 396 ++++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100644 src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 9702efbcfbcea..89db40727f908 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -24,6 +24,8 @@ import { AsyncIterableObject } from 'vs/base/common/async'; import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +// EXAMPLE +import { DummyResizeWidget } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { @@ -42,6 +44,9 @@ export class ContentHoverController extends Disposable { ) { super(); + // EXAMPLE + _editor.addContentWidget(new DummyResizeWidget(this._editor, new MultipleSizePersistingOptions())); + // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; for (const participant of HoverParticipantRegistry.getAll()) { diff --git a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts new file mode 100644 index 0000000000000..cba0053807d9b --- /dev/null +++ b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts @@ -0,0 +1,396 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { clamp } from 'vs/base/common/numbers'; +import { ResourceMap } from 'vs/base/common/map'; +import { IPosition } from 'vs/editor/common/core/position'; +import * as dom from 'vs/base/browser/dom'; + +export abstract class ExampleResizableContentWidget extends Disposable implements IContentWidget { + + allowEditorOverflow?: boolean | undefined; + suppressMouseDown?: boolean | undefined; + + protected readonly _contentNode: HTMLDivElement; + protected readonly _resizableNode = this._register(new ResizableHTMLElement()); + + private _position: IContentWidgetPosition | null = null; + protected readonly persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; + private resizing: boolean = false; + + constructor( + initalSize: dom.IDimension = new dom.Dimension(100, 100), + private readonly persistingOptions: IPersistingOptions, + protected readonly editor: ICodeEditor + ) { + super(); + this._contentNode = document.createElement('div'); + this._contentNode.style.width = `${initalSize.width}px`; + this._contentNode.style.height = `${initalSize.height}px`; + this._resizableNode.domNode.appendChild(this._contentNode); + this._resizableNode.minSize = new dom.Dimension(10, 10); + this._resizableNode.enableSashes(true, true, true, true); + this._resizableNode.layout(initalSize.height, initalSize.width); + this._register(this._resizableNode.onDidResize(e => { + this._contentNode.style.width = `${e.dimension.width}px`; + this._contentNode.style.height = `${e.dimension.height}px`; + })); + + if (this.persistingOptions instanceof SingleSizePersistingOptions) { + this.persistingMechanism = new SingleSizePersistingMechanism(this, this.editor, this.persistingOptions); + } else if (this.persistingOptions instanceof MultipleSizePersistingOptions) { + this.persistingMechanism = new MultipleSizePersistingMechanism(this, this.editor); + } else { + throw new Error('Please specify a valid persisting mechanism'); + } + + this._register(this._resizableNode.onDidWillResize(() => { + this.resizing = true; + })); + this._register(this._resizableNode.onDidResize((e) => { + if (e.done) { + this.resizing = false; + } + })); + } + + abstract getId(): string; + + + getDomNode(): HTMLElement { + return this._resizableNode.domNode; + } + + getPosition(): IContentWidgetPosition | null { + return this._position; + } + + setPosition(value: IContentWidgetPosition | null): void { + // TODO + // - compute boxed above/below if applicable + this._position = value; + } + + // abstract beforeRender?(): IDimension | null; + + afterRender(position: ContentWidgetPositionPreference | null): void { + // TODO + // - set max sizes that were computed above + } + + abstract resize(dimension: dom.Dimension): void; + + isResizing() { + return this.resizing; + } + + findPersistedSize(): dom.Dimension | undefined { + return this.persistingMechanism.findSize(); + } + + beforeOnDidWillResize() { + return; + } + + afterOnDidResize() { + return; + } + + get resizableNode(): ResizableHTMLElement { + return this._resizableNode; + } +} + +export class DummyResizeWidget extends ExampleResizableContentWidget { + + constructor( + editor: ICodeEditor, + persistingOptions: IPersistingOptions, + initalSize: dom.IDimension = new dom.Dimension(100, 100) + ) { + super(initalSize, persistingOptions, editor); + this._contentNode.style.backgroundColor = 'red'; + this._contentNode.classList.add('dummy'); + } + + override getId(): string { + return 'dummy'; + } + + override getPosition(): IContentWidgetPosition | null { + return { + position: { lineNumber: 1, column: 1 }, + preference: [ContentWidgetPositionPreference.BELOW] + }; + } + + public resize(size: dom.Dimension) { + this._contentNode.style.width = `${size.width}px`; + this._contentNode.style.height = `${size.height}px`; + this.editor.layoutContentWidget(this); + } + + // override beforeRender?(): IDimension | null { + // throw new Error('Method not implemented.'); + // } + // override afterRender?(position: ContentWidgetPositionPreference | null): void { + // throw new Error('Method not implemented.'); + // } +} + + + + +// --- OLD PERSISTING MECHANISM + +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 { + + /** + * Method which returns the current appropriate persisted size of the widget. + */ + findSize(): dom.Dimension | undefined; + + /** + * Method which clears the persisted size(s) of the widget. + */ + clear(): void; + + /** + * Method which disposes the persisting mechanism. + */ + dispose(): void; +} + +/** + * Class which can be used to define a mechanism that persists the size of a resizable widget. The persisted size is stored using the storage service. + */ +export class SingleSizePersistingMechanism implements IPersistingMechanism { + + private readonly persistedWidgetSize: PersistedWidgetSize | null = null; + private readonly disposables = new DisposableStore(); + + constructor( + private readonly resizableWidget: ExampleResizableContentWidget, + private readonly editor: ICodeEditor, + private readonly persistingOptions: SingleSizePersistingOptions + ) { + + this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); + + let state: ResizeState | undefined; + this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { + this.resizableWidget.beforeOnDidWillResize(); + state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.resizableNode.size); + })); + this.disposables.add(this.resizableWidget.resizableNode.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.resizableWidget.resizableNode.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)); + } + state = undefined; + this.resizableWidget.afterOnDidResize(); + })); + } + + findSize(): dom.Dimension | undefined { + return this.persistedWidgetSize?.restore(); + } + + clear(): void { + this.persistedWidgetSize?.reset(); + } + + dispose(): void { + this.disposables.dispose(); + } +} + +/** + * Class which can be used to define a mechanism which persists the sizes of a resizable widget on a per token-basis. + * The sizes are saved in a ResourceMap which maps the document URI to the token position and its dom.Dimension persisted size. + */ +export class MultipleSizePersistingMechanism implements IPersistingMechanism { + + private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); + private readonly disposables = new DisposableStore(); + private _position: IPosition | null = null; + + constructor( + private readonly resizableWidget: ExampleResizableContentWidget, + public readonly editor: ICodeEditor + ) { + 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(); + 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.resizableWidget.resizableNode.onDidWillResize(() => { + this.resizableWidget.beforeOnDidWillResize(); + })); + this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { + const height = e.dimension.height; + const width = e.dimension.width; + this.resizableWidget.resize(new dom.Dimension(width, height)); + if (e.done) { + if (!this.editor.hasModel()) { + return; + } + const uri = this.editor.getModel().uri; + if (!uri || !this._position) { + return; + } + const persistedSize = new dom.Dimension(width, height); + const wordPosition = this.editor.getModel().getWordAtPosition(this._position); + if (!wordPosition) { + return; + } + const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); + const length = wordPosition.word.length; + + if (!this.persistedWidgetSizes.get(uri)) { + const persistedWidgetSizesForUri = new Map([]); + 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.resizableWidget.afterOnDidResize(); + })); + } + + set position(position: IPosition) { + this._position = position; + } + + findSize(): dom.Dimension | undefined { + if (!this._position || !this.editor.hasModel()) { + return; + } + const wordPosition = this.editor.getModel().getWordAtPosition(this._position); + if (!wordPosition) { + return; + } + const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.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])); + } + + clear(): void { + this.persistedWidgetSizes.clear(); + } + + dispose(): void { + this.disposables.dispose(); + } +} + +/** + * Class which is used in the single size persisting mechanism for resizable widgets. + */ +class PersistedWidgetSize { + + constructor( + private readonly _key: string, + private readonly _service: IStorageService + ) { } + + 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); + } +} + +/** + * Class which is used in the single size persisting mechanism for resizable widgets. + */ +class ResizeState { + constructor( + readonly persistedSize: dom.Dimension | undefined, + readonly currentSize: dom.Dimension, + public persistHeight = false, + public persistWidth = false, + ) { } +} From 1dbecaee2eb2390419586e4f31a7687690ea55b0 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 12 Apr 2023 15:34:26 +0200 Subject: [PATCH 45/72] adding the initial code into the example resizable content widget --- .../contrib/hover/browser/contentHover.ts | 6 +- .../browser/exampleResizableContentWidget.ts | 516 +++++++++++++++++- 2 files changed, 503 insertions(+), 19 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 89db40727f908..90fe9f94dbd76 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -25,7 +25,7 @@ import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, Resizab import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; // EXAMPLE -import { DummyResizeWidget } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; +import { DummyResizeWidget, ExampleMultipleSizePersistingOptions } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { @@ -45,7 +45,7 @@ export class ContentHoverController extends Disposable { super(); // EXAMPLE - _editor.addContentWidget(new DummyResizeWidget(this._editor, new MultipleSizePersistingOptions())); + _editor.addContentWidget(new DummyResizeWidget(this._editor, new ExampleMultipleSizePersistingOptions())); // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; @@ -434,7 +434,7 @@ class FilteredHoverResult extends HoverResult { } } -class ContentHoverVisibleData { +export class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; diff --git a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts index cba0053807d9b..d6400b6fe7ddd 100644 --- a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts @@ -7,11 +7,19 @@ import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { clamp } from 'vs/base/common/numbers'; import { ResourceMap } from 'vs/base/common/map'; -import { IPosition } from 'vs/editor/common/core/position'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import * as dom from 'vs/base/browser/dom'; +import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; +import { ContentHoverVisibleData } from 'vs/editor/contrib/hover/browser/contentHover'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; +import { PositionAffinity } from 'vs/editor/common/model'; + +// TODO: add my code, then do the TODOs export abstract class ExampleResizableContentWidget extends Disposable implements IContentWidget { @@ -21,8 +29,8 @@ export abstract class ExampleResizableContentWidget extends Disposable implement protected readonly _contentNode: HTMLDivElement; protected readonly _resizableNode = this._register(new ResizableHTMLElement()); - private _position: IContentWidgetPosition | null = null; - protected readonly persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; + private _contentPosition: IContentWidgetPosition | null = null; + protected readonly persistingMechanism: ExampleSingleSizePersistingMechanism | ExampleMultipleSizePersistingMechanism; private resizing: boolean = false; constructor( @@ -43,10 +51,10 @@ export abstract class ExampleResizableContentWidget extends Disposable implement this._contentNode.style.height = `${e.dimension.height}px`; })); - if (this.persistingOptions instanceof SingleSizePersistingOptions) { - this.persistingMechanism = new SingleSizePersistingMechanism(this, this.editor, this.persistingOptions); - } else if (this.persistingOptions instanceof MultipleSizePersistingOptions) { - this.persistingMechanism = new MultipleSizePersistingMechanism(this, this.editor); + if (this.persistingOptions instanceof ExampleSingleSizePersistingOptions) { + this.persistingMechanism = new ExampleSingleSizePersistingMechanism(this, this.editor, this.persistingOptions); + } else if (this.persistingOptions instanceof ExampleMultipleSizePersistingOptions) { + this.persistingMechanism = new ExampleMultipleSizePersistingMechanism(this, this.editor); } else { throw new Error('Please specify a valid persisting mechanism'); } @@ -63,19 +71,18 @@ export abstract class ExampleResizableContentWidget extends Disposable implement abstract getId(): string; - getDomNode(): HTMLElement { return this._resizableNode.domNode; } getPosition(): IContentWidgetPosition | null { - return this._position; + return this._contentPosition; } setPosition(value: IContentWidgetPosition | null): void { // TODO // - compute boxed above/below if applicable - this._position = value; + this._contentPosition = value; } // abstract beforeRender?(): IDimension | null; @@ -140,19 +147,488 @@ export class DummyResizeWidget extends ExampleResizableContentWidget { // override beforeRender?(): IDimension | null { // throw new Error('Method not implemented.'); // } + // override afterRender?(position: ContentWidgetPositionPreference | null): void { // throw new Error('Method not implemented.'); // } } +const SCROLLBAR_WIDTH = 10; +const SASH_WIDTH_MINUS_BORDER = 3; +const BORDER_WIDTH = 1; +const DELTA_SASH_LENGTH = 4; + +export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { + + public static ID = 'editor.contrib.resizableContentHoverWidget'; + + private disposableStore = new DisposableStore(); + private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); + private visibleData: ContentHoverVisibleData | null = null; + private renderingAbove: ContentWidgetPositionPreference | null = null; + private visible: boolean = false; + + private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); + private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); + private readonly focusTracker: dom.IFocusTracker; + private readonly horizontalScrollingBy: number = 30; + + private _position: IPosition | null = null; + private _secondaryPosition: IPosition | null = null; + private _preference: ContentWidgetPositionPreference[] = []; + private _positionAffinity: PositionAffinity | undefined = undefined; + + constructor( + editor: ICodeEditor, + @IContextKeyService private readonly contextKeyService: IContextKeyService + ) { + const initalSize = new dom.Dimension(10, 10); + const persistingOptions = new ExampleMultipleSizePersistingOptions(); + super(initalSize, persistingOptions, editor); + this.resizableNode.domNode.style.position = 'absolute'; + this.resizableNode.domNode.style.zIndex = '50'; + dom.append(this.resizableNode.domNode, this.hoverWidget.containerDomNode); + this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); + this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); + this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { + this._updateFont(); + } + })); + this.disposableStore.add(this.focusTracker.onDidFocus(() => { + this.hoverFocusedKey.set(true); + })); + this.disposableStore.add(this.focusTracker.onDidBlur(() => { + this.hoverFocusedKey.set(false); + })); + this._setVisibleData(null); + this._layout(); + } + + public get position(): Position | null { + return this.visibleData?.showAtPosition ?? null; + } + + public get isColorPickerVisible(): boolean { + return Boolean(this.visibleData?.colorPicker); + } + + public get isVisibleFromKeyboard(): boolean { + return (this.visibleData?.source === HoverStartSource.Keyboard); + } + + public get isVisible(): boolean { + return this.hoverVisibleKey.get() ?? false; + } + + public getId(): string { + return ExampleResizableHoverWidget.ID; + } + + public resize(size: dom.Dimension) { + + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + + const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.hoverWidget.containerDomNode.style.width = width; + this.hoverWidget.contentsDomNode.style.width = width; + + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + + if (hasHorizontalScrollbar) { + // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + } + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this.hoverWidget.containerDomNode.style.height = height + 'px'; + this.hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; + } else { + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this.hoverWidget.containerDomNode.style.height = height + 'px'; + this.hoverWidget.contentsDomNode.style.height = height + 'px'; + } + + const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; + this.resizableNode.northSash.el.style.width = horizontalSashLength; + this.resizableNode.southSash.el.style.width = horizontalSashLength; + this.resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; + this.resizableNode.eastSash.el.style.height = verticalSashLength; + this.resizableNode.westSash.el.style.height = verticalSashLength; + this.resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + + const maxRenderingWidth = this.findMaximumRenderingWidth(); + const maxRenderingHeight = this.findMaximumRenderingHeight(); + if (!maxRenderingWidth || !maxRenderingHeight) { + return; + } + this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); + this.hoverWidget.scrollbar.scanDomNode(); + this.editor.layoutContentWidget(this); + } + + public findAvailableSpaceVertically(): number | undefined { + if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); + const bodyBox = dom.getClientArea(document.body); + let availableSpace: number; + + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + availableSpace = editorBox.top + mouseBox.top - 30; + } else { + const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; + availableSpace = bodyBox.height - mouseBottom; + } + return availableSpace; + } + + public findAvailableSpaceHorizontally(): number | undefined { + return this.findMaximumRenderingWidth(); + } + + public findMaximumRenderingHeight(): number | undefined { + + const availableSpace = this.findAvailableSpaceVertically(); + if (!availableSpace) { + return; + } + let divMaxHeight = 3 * SASH_WIDTH_MINUS_BORDER; + for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { + divMaxHeight += childHtmlElement.clientHeight; + } + if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { + divMaxHeight += SCROLLBAR_WIDTH; + } + return Math.min(availableSpace, divMaxHeight); + } + + public findMaximumRenderingWidth(): number | undefined { + if (!this.editor || !this.editor.hasModel()) { + return; + } + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const widthOfEditor = editorBox.width; + const leftOfEditor = editorBox.left; + const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; + const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; + return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; + } + public override dispose(): void { + this.editor.removeContentWidget(this); + if (this.visibleData) { + this.visibleData.disposables.dispose(); + } + super.dispose(); + } + public isMouseGettingCloser(posx: number, posy: number): boolean { + if (!this.visibleData) { + return false; + } + if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { + this.visibleData.initialMousePosX = posx; + this.visibleData.initialMousePosY = posy; + return false; + } + + const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); + if (typeof this.visibleData.closestMouseDistance === 'undefined') { + this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + } + const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + // The mouse is getting farther away + return false; + } + this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); + return true; + } + + private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { + if (this.visibleData) { + this.visibleData.disposables.dispose(); + } + this.visibleData = visibleData; + this.hoverVisibleKey.set(!!this.visibleData); + this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); + } + + private _layout(): void { + const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); + const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); + + this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; + this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + } + + private _updateFont(): void { + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); + codeClasses.forEach(node => this.editor.applyFontInfo(node)); + } + + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + if (!this.editor || !this.editor.hasModel()) { + return; + } + if (this.persistingMechanism instanceof ExampleMultipleSizePersistingMechanism) { + this.persistingMechanism.position = visibleData.showAtPosition; + } + this._position = visibleData.showAtPosition; + this._secondaryPosition = visibleData.showAtSecondaryPosition; + this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + this._setVisibleData(visibleData); + + if (!this.visible) { + this.editor.addContentWidget(this); + } + + this.hoverWidget.contentsDomNode.textContent = ''; + this.hoverWidget.contentsDomNode.appendChild(node); + this.hoverWidget.contentsDomNode.style.paddingBottom = ''; + this._updateFont(); + + let height; + const persistedSize = this.findPersistedSize(); + // If there is no persisted size, then normally render + if (!persistedSize) { + this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this.editor.render(); + height = this.hoverWidget.containerDomNode.clientHeight + 6; + } + // When there is a persisted size then do not use a maximum height or width + else { + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + height = persistedSize.height; + } + + // The dimensions of the document in which we are displaying the hover + const bodyBox = dom.getClientArea(document.body); + // Hard-coded in the hover.css file as 1.5em or 24px + const minHeight = 24; + // The full height is already passed in as a parameter + const fullHeight = height; + const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); + // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height + const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; + // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position + const availableSpaceBelow = bodyBox.height - mouseBottom; + // Max height below is the minimum of the available space below and the full height of the widget + const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); + // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor + const availableSpaceAbove = editorBox.top + mouseBox.top - 30; + const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); + // We find the maximum height of the widget possible on the top or on the bottom + const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); + + if (height < minHeight) { + height = minHeight; + } + if (height > maxHeight) { + height = maxHeight; + } + + // Determining whether we should render above or not ideally + if (this.editor.getOption(EditorOption.hover).above) { + this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + } else { + this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + } + + if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + this.resizableNode.enableSashes(true, true, false, false); + } else { + this.resizableNode.enableSashes(false, true, true, false); + } + + this._preference = [this.renderingAbove]; + + // See https://github.com/microsoft/vscode/issues/140339 + // TODO: Doing a second layout of the hover after force rendering the editor + if (!persistedSize) { + this.onContentsChanged(); + } + + if (visibleData.stoleFocus) { + this.hoverWidget.containerDomNode.focus(); + } + visibleData.colorPicker?.layout(); + this.visible = true; + } + + public hide(): void { + this.visible = false; + this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); + this.resizableNode.clearSashHoverState(); + this.editor.removeContentWidget(this); + if (this.visibleData) { + const stoleFocus = this.visibleData.stoleFocus; + this._setVisibleData(null); + this.editor.layoutContentWidget(this); + if (stoleFocus) { + this.editor.focus(); + } + } + } + + private _layoutContentWidget(): void { + this.editor.layoutContentWidget(this); + this.hoverWidget.onContentsChanged(); + } + + public onContentsChanged(): void { + const persistedSize = this.findPersistedSize(); + const containerDomNode = this.hoverWidget.containerDomNode; + const contentsDomNode = this.hoverWidget.contentsDomNode; + + // Suppose a persisted size is defined + if (persistedSize) { + const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); + const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); + containerDomNode.style.width = width + 'px'; + containerDomNode.style.height = height + 'px'; + contentsDomNode.style.width = width + 'px'; + contentsDomNode.style.height = height + 'px'; + this._layoutContentWidget(); + } else { + containerDomNode.style.width = 'auto'; + containerDomNode.style.height = 'auto'; + contentsDomNode.style.width = 'auto'; + contentsDomNode.style.height = 'auto'; + // Added because otherwise the initial size of the hover content is smaller than should be + this.resizableNode.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; + this.resizableNode.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; + this._layoutContentWidget(); + // Added otherwise rendered too small horizontally + containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; + } + + const clientHeight = containerDomNode.clientHeight; + const clientWidth = containerDomNode.clientWidth; + + this.resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); + this.resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + + containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + + const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); + if (hasHorizontalScrollbar) { + const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + } + const maxRenderingHeight = this.findMaximumRenderingHeight(); + if (!maxRenderingHeight) { + return; + } + if (persistedSize) { + const persistedHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; + containerDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight - SCROLLBAR_WIDTH) + 'px'; + } else { + containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; + contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; + } + } + + const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; + const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; + + this.resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; + this.resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; + this.resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; + this.resizableNode.westSash.el.style.height = verticalSashLength + 'px'; + this.resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._layoutContentWidget(); + } + + public clear(): void { + this.hoverWidget.contentsDomNode.textContent = ''; + } + + public focus(): void { + this.hoverWidget.containerDomNode.focus(); + } + + public scrollUp(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); + } + + public scrollDown(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); + } + + public scrollLeft(): void { + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); + } + + public scrollRight(): void { + const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); + } + + public pageUp(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); + } + + public pageDown(): void { + const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); + } + + public goToTop(): void { + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); + } + + public goToBottom(): void { + this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); + } + + public escape(): void { + this.editor.focus(); + } + + public clearPersistedSizes(): void { + this.persistingMechanism.clear(); + } +} // --- OLD PERSISTING MECHANISM interface IPersistingOptions { } -export class SingleSizePersistingOptions implements IPersistingOptions { +export class ExampleSingleSizePersistingOptions implements IPersistingOptions { constructor( public readonly key: string, public readonly defaultSize: dom.Dimension, @@ -160,7 +636,7 @@ export class SingleSizePersistingOptions implements IPersistingOptions { ) { } } -export class MultipleSizePersistingOptions implements IPersistingOptions { +export class ExampleMultipleSizePersistingOptions implements IPersistingOptions { constructor() { } } @@ -185,7 +661,7 @@ interface IPersistingMechanism extends IDisposable { /** * Class which can be used to define a mechanism that persists the size of a resizable widget. The persisted size is stored using the storage service. */ -export class SingleSizePersistingMechanism implements IPersistingMechanism { +export class ExampleSingleSizePersistingMechanism implements IPersistingMechanism { private readonly persistedWidgetSize: PersistedWidgetSize | null = null; private readonly disposables = new DisposableStore(); @@ -193,7 +669,7 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { constructor( private readonly resizableWidget: ExampleResizableContentWidget, private readonly editor: ICodeEditor, - private readonly persistingOptions: SingleSizePersistingOptions + private readonly persistingOptions: ExampleSingleSizePersistingOptions ) { this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); @@ -247,7 +723,7 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { * Class which can be used to define a mechanism which persists the sizes of a resizable widget on a per token-basis. * The sizes are saved in a ResourceMap which maps the document URI to the token position and its dom.Dimension persisted size. */ -export class MultipleSizePersistingMechanism implements IPersistingMechanism { +export class ExampleMultipleSizePersistingMechanism implements IPersistingMechanism { private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); private readonly disposables = new DisposableStore(); @@ -394,3 +870,11 @@ class ResizeState { public persistWidth = false, ) { } } + +function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { + const x = (left + width / 2); // x center of rectangle + const y = (top + height / 2); // y center of rectangle + const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); + const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); + return Math.sqrt(dx * dx + dy * dy); +} From 955f6a09f3c985b1fff52cb57f3ab160f4b39650 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 27 Apr 2023 15:16:24 +0200 Subject: [PATCH 46/72] setting the position, now the hover appears, need to clean the code --- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index bf53f53d98557..a6b32e81b160f 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -691,7 +691,7 @@ class ClearPersistedHoverSizes extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { const controller = ModesHoverController.get(editor); if (!controller) { return; From 8341580bfc1a53c0e18011e8642fc99b4e3da806 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 27 Apr 2023 15:32:59 +0200 Subject: [PATCH 47/72] setting the position of the content widget inside of the showAt function --- src/vs/base/browser/ui/resizable/resizable.ts | 1 - .../contrib/hover/browser/contentHover.ts | 22 +++++++++---- .../browser/exampleResizableContentWidget.ts | 31 +++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index e53a6542724a7..d71281f3dc135 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -168,7 +168,6 @@ export class ResizableHTMLElement { this._size = size; } - set maxSize(value: Dimension) { this._maxSize = value; } diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 90fe9f94dbd76..cab214423803f 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -24,14 +24,15 @@ import { AsyncIterableObject } from 'vs/base/common/async'; import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -// EXAMPLE -import { DummyResizeWidget, ExampleMultipleSizePersistingOptions } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; +import { ExampleResizableHoverWidget } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; +// EXAMPLE : import { DummyResizeWidget, ExampleMultipleSizePersistingOptions } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - private readonly _widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); + // private readonly _widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); + private readonly _widget = this._register(this._instantiationService.createInstance(ExampleResizableHoverWidget, this._editor)); private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; @@ -41,11 +42,11 @@ export class ContentHoverController extends Disposable { private readonly _editor: ICodeEditor, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IKeybindingService private readonly _keybindingService: IKeybindingService, + @IContextKeyService _contextKeyService: IContextKeyService ) { super(); - - // EXAMPLE - _editor.addContentWidget(new DummyResizeWidget(this._editor, new ExampleMultipleSizePersistingOptions())); + // EXAMPLE : _editor.addContentWidget(new DummyResizeWidget(this._editor, new ExampleMultipleSizePersistingOptions())); + // _editor.addContentWidget(new ExampleResizableHoverWidget(_editor, _contextKeyService)); // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; @@ -190,6 +191,9 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { + console.log('Inside of _setCurrentResult'); + console.log('hoverResult: ', hoverResult); + if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -260,6 +264,9 @@ export class ContentHoverController extends Disposable { } private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void { + + console.log('Inside of _renderMessages'); + const { showAtPosition, showAtSecondaryPosition, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages); const disposables = new DisposableStore(); @@ -300,6 +307,7 @@ export class ContentHoverController extends Disposable { })); } + console.log('Right before the showAt function of the _renderMessages function'); this._widget.showAt(fragment, new ContentHoverVisibleData( colorPicker, showAtPosition, @@ -790,6 +798,8 @@ export class ResizableHoverWidget extends ResizableWidget { } public onContentsChanged(): void { + console.log('Inside of on content changed'); + const persistedSize = this.findPersistedSize(); const containerDomNode = this.hoverWidget.containerDomNode; const contentsDomNode = this.hoverWidget.contentsDomNode; diff --git a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts index d6400b6fe7ddd..93e6334af68a8 100644 --- a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts @@ -72,14 +72,17 @@ export abstract class ExampleResizableContentWidget extends Disposable implement abstract getId(): string; getDomNode(): HTMLElement { + console.log('Inside of getDomNode of ExampleResizableContentWidget : ', this._resizableNode.domNode); return this._resizableNode.domNode; } getPosition(): IContentWidgetPosition | null { + console.log('Inside of getPosition, this._contentPosition : ', this._contentPosition); return this._contentPosition; } setPosition(value: IContentWidgetPosition | null): void { + console.log('Inside of setPosition, value : ', value); // TODO // - compute boxed above/below if applicable this._contentPosition = value; @@ -182,6 +185,8 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { editor: ICodeEditor, @IContextKeyService private readonly contextKeyService: IContextKeyService ) { + console.log('Inside of the constructor of the ExampleResizableHoverWidget'); + const initalSize = new dom.Dimension(10, 10); const persistingOptions = new ExampleMultipleSizePersistingOptions(); super(initalSize, persistingOptions, editor); @@ -227,6 +232,8 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { public resize(size: dom.Dimension) { + console.log('Inside of the resize function'); + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; @@ -379,6 +386,8 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + console.log('Inside of the showAt function'); + if (!this.editor || !this.editor.hasModel()) { return; } @@ -388,9 +397,19 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { this._position = visibleData.showAtPosition; this._secondaryPosition = visibleData.showAtSecondaryPosition; this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + + // --- + // Fixing the position data + const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; + this.setPosition(widgetPosition); + // --- + this._setVisibleData(visibleData); + console.log('this.visible : ', this.visible); + if (!this.visible) { + console.log('right before adding the content widget'); this.editor.addContentWidget(this); } @@ -401,6 +420,8 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { let height; const persistedSize = this.findPersistedSize(); + console.log('persistedSize : ', persistedSize); + // If there is no persisted size, then normally render if (!persistedSize) { this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; @@ -460,6 +481,11 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { this._preference = [this.renderingAbove]; + // -- Fixing the position + widgetPosition.preference = this._preference; + this.setPosition(widgetPosition); + // --- + // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!persistedSize) { @@ -474,6 +500,8 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { } public hide(): void { + console.log('Inside of the hide function'); + this.visible = false; this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); this.resizableNode.clearSashHoverState(); @@ -494,6 +522,9 @@ export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { } public onContentsChanged(): void { + + console.log('Inside of onContentsChanged'); + const persistedSize = this.findPersistedSize(); const containerDomNode = this.hoverWidget.containerDomNode; const contentsDomNode = this.hoverWidget.contentsDomNode; From 181d17177486d0236465826e6c5f2da7896a545e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 27 Apr 2023 15:57:30 +0200 Subject: [PATCH 48/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 180 ++-- .../browser/exampleResizableContentWidget.ts | 911 ------------------ src/vs/editor/contrib/hover/browser/hover.ts | 8 +- .../hover/browser/resizableContentWidget.ts | 211 ++-- 4 files changed, 160 insertions(+), 1150 deletions(-) delete mode 100644 src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index cab214423803f..715785060a20a 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -9,9 +9,9 @@ import { coalesce } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; -import { Position } from 'vs/editor/common/core/position'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IModelDecoration, PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; @@ -21,18 +21,15 @@ import { HoverAnchor, HoverAnchorType, HoverParticipantRegistry, HoverRangeAncho import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { AsyncIterableObject } from 'vs/base/common/async'; -import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { ExampleResizableHoverWidget } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; -// EXAMPLE : import { DummyResizeWidget, ExampleMultipleSizePersistingOptions } from 'vs/editor/contrib/hover/browser/exampleResizableContentWidget'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; - // private readonly _widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); - private readonly _widget = this._register(this._instantiationService.createInstance(ExampleResizableHoverWidget, this._editor)); + private readonly _widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation; @@ -42,11 +39,8 @@ export class ContentHoverController extends Disposable { private readonly _editor: ICodeEditor, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IContextKeyService _contextKeyService: IContextKeyService ) { super(); - // EXAMPLE : _editor.addContentWidget(new DummyResizeWidget(this._editor, new ExampleMultipleSizePersistingOptions())); - // _editor.addContentWidget(new ExampleResizableHoverWidget(_editor, _contextKeyService)); // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; @@ -442,7 +436,7 @@ class FilteredHoverResult extends HoverResult { } } -export class ContentHoverVisibleData { +class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; @@ -460,38 +454,45 @@ export class ContentHoverVisibleData { ) { } } + const SCROLLBAR_WIDTH = 10; const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; const DELTA_SASH_LENGTH = 4; -export class ResizableHoverWidget extends ResizableWidget { +export class ResizableHoverWidget extends ResizableContentWidget { + + public static ID = 'editor.contrib.resizableContentHoverWidget'; private disposableStore = new DisposableStore(); - private resizableContentWidget: ResizableContentHoverWidget; - private hoverWidget: HoverWidget; + private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); private visibleData: ContentHoverVisibleData | null = null; private renderingAbove: ContentWidgetPositionPreference | null = null; private visible: boolean = false; - public readonly allowEditorOverflow = true; private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); private readonly focusTracker: dom.IFocusTracker; private readonly horizontalScrollingBy: number = 30; + private _position: IPosition | null = null; + private _secondaryPosition: IPosition | null = null; + private _preference: ContentWidgetPositionPreference[] = []; + private _positionAffinity: PositionAffinity | undefined = undefined; + constructor( editor: ICodeEditor, @IContextKeyService private readonly contextKeyService: IContextKeyService ) { - super(editor, new MultipleSizePersistingOptions()); - this.element.domNode.style.position = 'absolute'; - this.element.domNode.style.zIndex = '50'; - - this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); - this.hoverWidget = this.resizableContentWidget.hoverWidget; + console.log('Inside of the constructor of the ExampleResizableHoverWidget'); + + const initalSize = new dom.Dimension(10, 10); + const persistingOptions = new MultipleSizePersistingOptions(); + super(initalSize, persistingOptions, editor); + this.resizableNode.domNode.style.position = 'absolute'; + this.resizableNode.domNode.style.zIndex = '50'; + dom.append(this.resizableNode.domNode, this.hoverWidget.containerDomNode); this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); - this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { @@ -524,8 +525,14 @@ export class ResizableHoverWidget extends ResizableWidget { return this.hoverVisibleKey.get() ?? false; } + public getId(): string { + return ResizableHoverWidget.ID; + } + public resize(size: dom.Dimension) { + console.log('Inside of the resize function'); + this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; @@ -552,24 +559,24 @@ export class ResizableHoverWidget extends ResizableWidget { } const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - this.element.northSash.el.style.width = horizontalSashLength; - this.element.southSash.el.style.width = horizontalSashLength; - this.element.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - this.element.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.northSash.el.style.width = horizontalSashLength; + this.resizableNode.southSash.el.style.width = horizontalSashLength; + this.resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - this.element.eastSash.el.style.height = verticalSashLength; - this.element.westSash.el.style.height = verticalSashLength; - this.element.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - this.element.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.eastSash.el.style.height = verticalSashLength; + this.resizableNode.westSash.el.style.height = verticalSashLength; + this.resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this.resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; const maxRenderingWidth = this.findMaximumRenderingWidth(); const maxRenderingHeight = this.findMaximumRenderingHeight(); if (!maxRenderingWidth || !maxRenderingHeight) { return; } - this.element.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); + this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); this.hoverWidget.scrollbar.scanDomNode(); - this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.layoutContentWidget(this); } public findAvailableSpaceVertically(): number | undefined { @@ -587,7 +594,6 @@ export class ResizableHoverWidget extends ResizableWidget { const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; availableSpace = bodyBox.height - mouseBottom; } - return availableSpace; } @@ -624,17 +630,13 @@ export class ResizableHoverWidget extends ResizableWidget { } public override dispose(): void { - this.editor.removeContentWidget(this.resizableContentWidget); + this.editor.removeContentWidget(this); if (this.visibleData) { this.visibleData.disposables.dispose(); } super.dispose(); } - public getDomNode() { - return this.hoverWidget.containerDomNode; - } - public isMouseGettingCloser(posx: number, posy: number): boolean { if (!this.visibleData) { return false; @@ -645,7 +647,7 @@ export class ResizableHoverWidget extends ResizableWidget { return false; } - const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); + const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); if (typeof this.visibleData.closestMouseDistance === 'undefined') { this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } @@ -683,19 +685,31 @@ export class ResizableHoverWidget extends ResizableWidget { } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + console.log('Inside of the showAt function'); + if (!this.editor || !this.editor.hasModel()) { return; } if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { this.persistingMechanism.position = visibleData.showAtPosition; } - this.resizableContentWidget.position = visibleData.showAtPosition; - this.resizableContentWidget.secondaryPosition = visibleData.showAtSecondaryPosition; - this.resizableContentWidget.positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + this._position = visibleData.showAtPosition; + this._secondaryPosition = visibleData.showAtSecondaryPosition; + this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + + // --- + // Fixing the position data + const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; + this.setPosition(widgetPosition); + // --- + this._setVisibleData(visibleData); + console.log('this.visible : ', this.visible); + if (!this.visible) { - this.editor.addContentWidget(this.resizableContentWidget); + console.log('right before adding the content widget'); + this.editor.addContentWidget(this); } this.hoverWidget.contentsDomNode.textContent = ''; @@ -705,6 +719,8 @@ export class ResizableHoverWidget extends ResizableWidget { let height; const persistedSize = this.findPersistedSize(); + console.log('persistedSize : ', persistedSize); + // If there is no persisted size, then normally render if (!persistedSize) { this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; @@ -713,7 +729,7 @@ export class ResizableHoverWidget extends ResizableWidget { // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this.editor.render(); - height = this.resizableContentWidget.getDomNode().clientHeight + 6; + height = this.hoverWidget.containerDomNode.clientHeight + 6; } // When there is a persisted size then do not use a maximum height or width else { @@ -757,12 +773,17 @@ export class ResizableHoverWidget extends ResizableWidget { } if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { - this.element.enableSashes(true, true, false, false); + this.resizableNode.enableSashes(true, true, false, false); } else { - this.element.enableSashes(false, true, true, false); + this.resizableNode.enableSashes(false, true, true, false); } - this.resizableContentWidget.preference = [this.renderingAbove]; + this._preference = [this.renderingAbove]; + + // -- Fixing the position + widgetPosition.preference = this._preference; + this.setPosition(widgetPosition); + // --- // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor @@ -778,14 +799,16 @@ export class ResizableHoverWidget extends ResizableWidget { } public hide(): void { + console.log('Inside of the hide function'); + this.visible = false; - this.element.maxSize = new dom.Dimension(Infinity, Infinity); - this.element.clearSashHoverState(); - this.editor.removeContentWidget(this.resizableContentWidget); + this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); + this.resizableNode.clearSashHoverState(); + this.editor.removeContentWidget(this); if (this.visibleData) { const stoleFocus = this.visibleData.stoleFocus; this._setVisibleData(null); - this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.layoutContentWidget(this); if (stoleFocus) { this.editor.focus(); } @@ -793,12 +816,13 @@ export class ResizableHoverWidget extends ResizableWidget { } private _layoutContentWidget(): void { - this.editor.layoutContentWidget(this.resizableContentWidget); + this.editor.layoutContentWidget(this); this.hoverWidget.onContentsChanged(); } public onContentsChanged(): void { - console.log('Inside of on content changed'); + + console.log('Inside of onContentsChanged'); const persistedSize = this.findPersistedSize(); const containerDomNode = this.hoverWidget.containerDomNode; @@ -819,8 +843,8 @@ export class ResizableHoverWidget extends ResizableWidget { contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; // Added because otherwise the initial size of the hover content is smaller than should be - this.element.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; - this.element.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; + this.resizableNode.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; + this.resizableNode.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; this._layoutContentWidget(); // Added otherwise rendered too small horizontally containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; @@ -829,9 +853,9 @@ export class ResizableHoverWidget extends ResizableWidget { const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; - this.element.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this.element.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.element.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); + this.resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this.resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; @@ -860,14 +884,14 @@ export class ResizableHoverWidget extends ResizableWidget { const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; - this.element.northSash.el.style.width = horizontalSashLength + 'px'; - this.element.southSash.el.style.width = horizontalSashLength + 'px'; - this.element.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.element.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.element.eastSash.el.style.height = verticalSashLength + 'px'; - this.element.westSash.el.style.height = verticalSashLength + 'px'; - this.element.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.element.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; + this.resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; + this.resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; + this.resizableNode.westSash.el.style.height = verticalSashLength + 'px'; + this.resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this.resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; this._layoutContentWidget(); } @@ -930,26 +954,6 @@ export class ResizableHoverWidget extends ResizableWidget { } } -export class ResizableContentHoverWidget extends ResizableContentWidget { - - private _disposableStore = new DisposableStore(); - private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); - public static ID = 'editor.contrib.resizableContentHoverWidget'; - - constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { - super(resizableHoverWidget); - dom.append(resizableHoverWidget.element.domNode, this._hoverWidget.containerDomNode); - } - - public getId(): string { - return ResizableContentHoverWidget.ID; - } - - get hoverWidget() { - return this._hoverWidget; - } -} - class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { public readonly hoverElement: HTMLElement; diff --git a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts deleted file mode 100644 index 93e6334af68a8..0000000000000 --- a/src/vs/editor/contrib/hover/browser/exampleResizableContentWidget.ts +++ /dev/null @@ -1,911 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; -import { clamp } from 'vs/base/common/numbers'; -import { ResourceMap } from 'vs/base/common/map'; -import { IPosition, Position } from 'vs/editor/common/core/position'; -import * as dom from 'vs/base/browser/dom'; -import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; -import { ContentHoverVisibleData } from 'vs/editor/contrib/hover/browser/contentHover'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { PositionAffinity } from 'vs/editor/common/model'; - -// TODO: add my code, then do the TODOs - -export abstract class ExampleResizableContentWidget extends Disposable implements IContentWidget { - - allowEditorOverflow?: boolean | undefined; - suppressMouseDown?: boolean | undefined; - - protected readonly _contentNode: HTMLDivElement; - protected readonly _resizableNode = this._register(new ResizableHTMLElement()); - - private _contentPosition: IContentWidgetPosition | null = null; - protected readonly persistingMechanism: ExampleSingleSizePersistingMechanism | ExampleMultipleSizePersistingMechanism; - private resizing: boolean = false; - - constructor( - initalSize: dom.IDimension = new dom.Dimension(100, 100), - private readonly persistingOptions: IPersistingOptions, - protected readonly editor: ICodeEditor - ) { - super(); - this._contentNode = document.createElement('div'); - this._contentNode.style.width = `${initalSize.width}px`; - this._contentNode.style.height = `${initalSize.height}px`; - this._resizableNode.domNode.appendChild(this._contentNode); - this._resizableNode.minSize = new dom.Dimension(10, 10); - this._resizableNode.enableSashes(true, true, true, true); - this._resizableNode.layout(initalSize.height, initalSize.width); - this._register(this._resizableNode.onDidResize(e => { - this._contentNode.style.width = `${e.dimension.width}px`; - this._contentNode.style.height = `${e.dimension.height}px`; - })); - - if (this.persistingOptions instanceof ExampleSingleSizePersistingOptions) { - this.persistingMechanism = new ExampleSingleSizePersistingMechanism(this, this.editor, this.persistingOptions); - } else if (this.persistingOptions instanceof ExampleMultipleSizePersistingOptions) { - this.persistingMechanism = new ExampleMultipleSizePersistingMechanism(this, this.editor); - } else { - throw new Error('Please specify a valid persisting mechanism'); - } - - this._register(this._resizableNode.onDidWillResize(() => { - this.resizing = true; - })); - this._register(this._resizableNode.onDidResize((e) => { - if (e.done) { - this.resizing = false; - } - })); - } - - abstract getId(): string; - - getDomNode(): HTMLElement { - console.log('Inside of getDomNode of ExampleResizableContentWidget : ', this._resizableNode.domNode); - return this._resizableNode.domNode; - } - - getPosition(): IContentWidgetPosition | null { - console.log('Inside of getPosition, this._contentPosition : ', this._contentPosition); - return this._contentPosition; - } - - setPosition(value: IContentWidgetPosition | null): void { - console.log('Inside of setPosition, value : ', value); - // TODO - // - compute boxed above/below if applicable - this._contentPosition = value; - } - - // abstract beforeRender?(): IDimension | null; - - afterRender(position: ContentWidgetPositionPreference | null): void { - // TODO - // - set max sizes that were computed above - } - - abstract resize(dimension: dom.Dimension): void; - - isResizing() { - return this.resizing; - } - - findPersistedSize(): dom.Dimension | undefined { - return this.persistingMechanism.findSize(); - } - - beforeOnDidWillResize() { - return; - } - - afterOnDidResize() { - return; - } - - get resizableNode(): ResizableHTMLElement { - return this._resizableNode; - } -} - -export class DummyResizeWidget extends ExampleResizableContentWidget { - - constructor( - editor: ICodeEditor, - persistingOptions: IPersistingOptions, - initalSize: dom.IDimension = new dom.Dimension(100, 100) - ) { - super(initalSize, persistingOptions, editor); - this._contentNode.style.backgroundColor = 'red'; - this._contentNode.classList.add('dummy'); - } - - override getId(): string { - return 'dummy'; - } - - override getPosition(): IContentWidgetPosition | null { - return { - position: { lineNumber: 1, column: 1 }, - preference: [ContentWidgetPositionPreference.BELOW] - }; - } - - public resize(size: dom.Dimension) { - this._contentNode.style.width = `${size.width}px`; - this._contentNode.style.height = `${size.height}px`; - this.editor.layoutContentWidget(this); - } - - // override beforeRender?(): IDimension | null { - // throw new Error('Method not implemented.'); - // } - - // override afterRender?(position: ContentWidgetPositionPreference | null): void { - // throw new Error('Method not implemented.'); - // } -} - -const SCROLLBAR_WIDTH = 10; -const SASH_WIDTH_MINUS_BORDER = 3; -const BORDER_WIDTH = 1; -const DELTA_SASH_LENGTH = 4; - -export class ExampleResizableHoverWidget extends ExampleResizableContentWidget { - - public static ID = 'editor.contrib.resizableContentHoverWidget'; - - private disposableStore = new DisposableStore(); - private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); - private visibleData: ContentHoverVisibleData | null = null; - private renderingAbove: ContentWidgetPositionPreference | null = null; - private visible: boolean = false; - - private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); - private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); - private readonly focusTracker: dom.IFocusTracker; - private readonly horizontalScrollingBy: number = 30; - - private _position: IPosition | null = null; - private _secondaryPosition: IPosition | null = null; - private _preference: ContentWidgetPositionPreference[] = []; - private _positionAffinity: PositionAffinity | undefined = undefined; - - constructor( - editor: ICodeEditor, - @IContextKeyService private readonly contextKeyService: IContextKeyService - ) { - console.log('Inside of the constructor of the ExampleResizableHoverWidget'); - - const initalSize = new dom.Dimension(10, 10); - const persistingOptions = new ExampleMultipleSizePersistingOptions(); - super(initalSize, persistingOptions, editor); - this.resizableNode.domNode.style.position = 'absolute'; - this.resizableNode.domNode.style.zIndex = '50'; - dom.append(this.resizableNode.domNode, this.hoverWidget.containerDomNode); - this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); - this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); - this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { - if (e.hasChanged(EditorOption.fontInfo)) { - this._updateFont(); - } - })); - this.disposableStore.add(this.focusTracker.onDidFocus(() => { - this.hoverFocusedKey.set(true); - })); - this.disposableStore.add(this.focusTracker.onDidBlur(() => { - this.hoverFocusedKey.set(false); - })); - this._setVisibleData(null); - this._layout(); - } - - public get position(): Position | null { - return this.visibleData?.showAtPosition ?? null; - } - - public get isColorPickerVisible(): boolean { - return Boolean(this.visibleData?.colorPicker); - } - - public get isVisibleFromKeyboard(): boolean { - return (this.visibleData?.source === HoverStartSource.Keyboard); - } - - public get isVisible(): boolean { - return this.hoverVisibleKey.get() ?? false; - } - - public getId(): string { - return ExampleResizableHoverWidget.ID; - } - - public resize(size: dom.Dimension) { - - console.log('Inside of the resize function'); - - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - - const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.hoverWidget.containerDomNode.style.width = width; - this.hoverWidget.contentsDomNode.style.width = width; - - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - - if (hasHorizontalScrollbar) { - // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - } - const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this.hoverWidget.containerDomNode.style.height = height + 'px'; - this.hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; - } else { - const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this.hoverWidget.containerDomNode.style.height = height + 'px'; - this.hoverWidget.contentsDomNode.style.height = height + 'px'; - } - - const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - this.resizableNode.northSash.el.style.width = horizontalSashLength; - this.resizableNode.southSash.el.style.width = horizontalSashLength; - this.resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - this.resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - this.resizableNode.eastSash.el.style.height = verticalSashLength; - this.resizableNode.westSash.el.style.height = verticalSashLength; - this.resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - this.resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - - const maxRenderingWidth = this.findMaximumRenderingWidth(); - const maxRenderingHeight = this.findMaximumRenderingHeight(); - if (!maxRenderingWidth || !maxRenderingHeight) { - return; - } - this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); - this.hoverWidget.scrollbar.scanDomNode(); - this.editor.layoutContentWidget(this); - } - - public findAvailableSpaceVertically(): number | undefined { - if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { - return; - } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); - const bodyBox = dom.getClientArea(document.body); - let availableSpace: number; - - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableSpace = editorBox.top + mouseBox.top - 30; - } else { - const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; - availableSpace = bodyBox.height - mouseBottom; - } - return availableSpace; - } - - public findAvailableSpaceHorizontally(): number | undefined { - return this.findMaximumRenderingWidth(); - } - - public findMaximumRenderingHeight(): number | undefined { - - const availableSpace = this.findAvailableSpaceVertically(); - if (!availableSpace) { - return; - } - let divMaxHeight = 3 * SASH_WIDTH_MINUS_BORDER; - for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { - divMaxHeight += childHtmlElement.clientHeight; - } - if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { - divMaxHeight += SCROLLBAR_WIDTH; - } - return Math.min(availableSpace, divMaxHeight); - } - - public findMaximumRenderingWidth(): number | undefined { - if (!this.editor || !this.editor.hasModel()) { - return; - } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const widthOfEditor = editorBox.width; - const leftOfEditor = editorBox.left; - const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; - const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; - return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; - } - - public override dispose(): void { - this.editor.removeContentWidget(this); - if (this.visibleData) { - this.visibleData.disposables.dispose(); - } - super.dispose(); - } - - public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this.visibleData) { - return false; - } - if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { - this.visibleData.initialMousePosX = posx; - this.visibleData.initialMousePosY = posy; - return false; - } - - const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); - if (typeof this.visibleData.closestMouseDistance === 'undefined') { - this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - } - const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { - // The mouse is getting farther away - return false; - } - this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); - return true; - } - - private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { - if (this.visibleData) { - this.visibleData.disposables.dispose(); - } - this.visibleData = visibleData; - this.hoverVisibleKey.set(!!this.visibleData); - this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); - } - - private _layout(): void { - const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); - - this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; - this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - } - - private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); - codeClasses.forEach(node => this.editor.applyFontInfo(node)); - } - - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - console.log('Inside of the showAt function'); - - if (!this.editor || !this.editor.hasModel()) { - return; - } - if (this.persistingMechanism instanceof ExampleMultipleSizePersistingMechanism) { - this.persistingMechanism.position = visibleData.showAtPosition; - } - this._position = visibleData.showAtPosition; - this._secondaryPosition = visibleData.showAtSecondaryPosition; - this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - - // --- - // Fixing the position data - const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; - this.setPosition(widgetPosition); - // --- - - this._setVisibleData(visibleData); - - console.log('this.visible : ', this.visible); - - if (!this.visible) { - console.log('right before adding the content widget'); - this.editor.addContentWidget(this); - } - - this.hoverWidget.contentsDomNode.textContent = ''; - this.hoverWidget.contentsDomNode.appendChild(node); - this.hoverWidget.contentsDomNode.style.paddingBottom = ''; - this._updateFont(); - - let height; - const persistedSize = this.findPersistedSize(); - console.log('persistedSize : ', persistedSize); - - // If there is no persisted size, then normally render - if (!persistedSize) { - this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; - this.onContentsChanged(); - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this.editor.render(); - height = this.hoverWidget.containerDomNode.clientHeight + 6; - } - // When there is a persisted size then do not use a maximum height or width - else { - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; - height = persistedSize.height; - } - - // The dimensions of the document in which we are displaying the hover - const bodyBox = dom.getClientArea(document.body); - // Hard-coded in the hover.css file as 1.5em or 24px - const minHeight = 24; - // The full height is already passed in as a parameter - const fullHeight = height; - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); - // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height - const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position - const availableSpaceBelow = bodyBox.height - mouseBottom; - // Max height below is the minimum of the available space below and the full height of the widget - const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); - // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor - const availableSpaceAbove = editorBox.top + mouseBox.top - 30; - const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); - // We find the maximum height of the widget possible on the top or on the bottom - const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); - - if (height < minHeight) { - height = minHeight; - } - if (height > maxHeight) { - height = maxHeight; - } - - // Determining whether we should render above or not ideally - if (this.editor.getOption(EditorOption.hover).above) { - this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - } else { - this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; - } - - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { - this.resizableNode.enableSashes(true, true, false, false); - } else { - this.resizableNode.enableSashes(false, true, true, false); - } - - this._preference = [this.renderingAbove]; - - // -- Fixing the position - widgetPosition.preference = this._preference; - this.setPosition(widgetPosition); - // --- - - // See https://github.com/microsoft/vscode/issues/140339 - // TODO: Doing a second layout of the hover after force rendering the editor - if (!persistedSize) { - this.onContentsChanged(); - } - - if (visibleData.stoleFocus) { - this.hoverWidget.containerDomNode.focus(); - } - visibleData.colorPicker?.layout(); - this.visible = true; - } - - public hide(): void { - console.log('Inside of the hide function'); - - this.visible = false; - this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); - this.resizableNode.clearSashHoverState(); - this.editor.removeContentWidget(this); - if (this.visibleData) { - const stoleFocus = this.visibleData.stoleFocus; - this._setVisibleData(null); - this.editor.layoutContentWidget(this); - if (stoleFocus) { - this.editor.focus(); - } - } - } - - private _layoutContentWidget(): void { - this.editor.layoutContentWidget(this); - this.hoverWidget.onContentsChanged(); - } - - public onContentsChanged(): void { - - console.log('Inside of onContentsChanged'); - - const persistedSize = this.findPersistedSize(); - const containerDomNode = this.hoverWidget.containerDomNode; - const contentsDomNode = this.hoverWidget.contentsDomNode; - - // Suppose a persisted size is defined - if (persistedSize) { - const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); - const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); - containerDomNode.style.width = width + 'px'; - containerDomNode.style.height = height + 'px'; - contentsDomNode.style.width = width + 'px'; - contentsDomNode.style.height = height + 'px'; - this._layoutContentWidget(); - } else { - containerDomNode.style.width = 'auto'; - containerDomNode.style.height = 'auto'; - contentsDomNode.style.width = 'auto'; - contentsDomNode.style.height = 'auto'; - // Added because otherwise the initial size of the hover content is smaller than should be - this.resizableNode.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; - this.resizableNode.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; - this._layoutContentWidget(); - // Added otherwise rendered too small horizontally - containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; - } - - const clientHeight = containerDomNode.clientHeight; - const clientWidth = containerDomNode.clientWidth; - - this.resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this.resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - - containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; - } - const maxRenderingHeight = this.findMaximumRenderingHeight(); - if (!maxRenderingHeight) { - return; - } - if (persistedSize) { - const persistedHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight - SCROLLBAR_WIDTH) + 'px'; - } else { - containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; - } - } - - const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; - const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; - - this.resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; - this.resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; - this.resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; - this.resizableNode.westSash.el.style.height = verticalSashLength + 'px'; - this.resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this._layoutContentWidget(); - } - - public clear(): void { - this.hoverWidget.contentsDomNode.textContent = ''; - } - - public focus(): void { - this.hoverWidget.containerDomNode.focus(); - } - - public scrollUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); - } - - public scrollDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); - } - - public scrollLeft(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); - } - - public scrollRight(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); - } - - public pageUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); - } - - public pageDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); - } - - public goToTop(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); - } - - public goToBottom(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); - } - - public escape(): void { - this.editor.focus(); - } - - public clearPersistedSizes(): void { - this.persistingMechanism.clear(); - } -} - -// --- OLD PERSISTING MECHANISM - -interface IPersistingOptions { } - -export class ExampleSingleSizePersistingOptions implements IPersistingOptions { - constructor( - public readonly key: string, - public readonly defaultSize: dom.Dimension, - @IStorageService public readonly storageService: IStorageService - ) { } -} - -export class ExampleMultipleSizePersistingOptions implements IPersistingOptions { - constructor() { } -} - -interface IPersistingMechanism extends IDisposable { - - /** - * Method which returns the current appropriate persisted size of the widget. - */ - findSize(): dom.Dimension | undefined; - - /** - * Method which clears the persisted size(s) of the widget. - */ - clear(): void; - - /** - * Method which disposes the persisting mechanism. - */ - dispose(): void; -} - -/** - * Class which can be used to define a mechanism that persists the size of a resizable widget. The persisted size is stored using the storage service. - */ -export class ExampleSingleSizePersistingMechanism implements IPersistingMechanism { - - private readonly persistedWidgetSize: PersistedWidgetSize | null = null; - private readonly disposables = new DisposableStore(); - - constructor( - private readonly resizableWidget: ExampleResizableContentWidget, - private readonly editor: ICodeEditor, - private readonly persistingOptions: ExampleSingleSizePersistingOptions - ) { - - this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); - - let state: ResizeState | undefined; - this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { - this.resizableWidget.beforeOnDidWillResize(); - state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.resizableNode.size); - })); - this.disposables.add(this.resizableWidget.resizableNode.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.resizableWidget.resizableNode.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)); - } - state = undefined; - this.resizableWidget.afterOnDidResize(); - })); - } - - findSize(): dom.Dimension | undefined { - return this.persistedWidgetSize?.restore(); - } - - clear(): void { - this.persistedWidgetSize?.reset(); - } - - dispose(): void { - this.disposables.dispose(); - } -} - -/** - * Class which can be used to define a mechanism which persists the sizes of a resizable widget on a per token-basis. - * The sizes are saved in a ResourceMap which maps the document URI to the token position and its dom.Dimension persisted size. - */ -export class ExampleMultipleSizePersistingMechanism implements IPersistingMechanism { - - private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); - private readonly disposables = new DisposableStore(); - private _position: IPosition | null = null; - - constructor( - private readonly resizableWidget: ExampleResizableContentWidget, - public readonly editor: ICodeEditor - ) { - 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(); - 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.resizableWidget.resizableNode.onDidWillResize(() => { - this.resizableWidget.beforeOnDidWillResize(); - })); - this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { - const height = e.dimension.height; - const width = e.dimension.width; - this.resizableWidget.resize(new dom.Dimension(width, height)); - if (e.done) { - if (!this.editor.hasModel()) { - return; - } - const uri = this.editor.getModel().uri; - if (!uri || !this._position) { - return; - } - const persistedSize = new dom.Dimension(width, height); - const wordPosition = this.editor.getModel().getWordAtPosition(this._position); - if (!wordPosition) { - return; - } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); - const length = wordPosition.word.length; - - if (!this.persistedWidgetSizes.get(uri)) { - const persistedWidgetSizesForUri = new Map([]); - 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.resizableWidget.afterOnDidResize(); - })); - } - - set position(position: IPosition) { - this._position = position; - } - - findSize(): dom.Dimension | undefined { - if (!this._position || !this.editor.hasModel()) { - return; - } - const wordPosition = this.editor.getModel().getWordAtPosition(this._position); - if (!wordPosition) { - return; - } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.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])); - } - - clear(): void { - this.persistedWidgetSizes.clear(); - } - - dispose(): void { - this.disposables.dispose(); - } -} - -/** - * Class which is used in the single size persisting mechanism for resizable widgets. - */ -class PersistedWidgetSize { - - constructor( - private readonly _key: string, - private readonly _service: IStorageService - ) { } - - 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); - } -} - -/** - * Class which is used in the single size persisting mechanism for resizable widgets. - */ -class ResizeState { - constructor( - readonly persistedSize: dom.Dimension | undefined, - readonly currentSize: dom.Dimension, - public persistHeight = false, - public persistWidth = false, - ) { } -} - -function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { - const x = (left + width / 2); // x center of rectangle - const y = (top + height / 2); // y center of rectangle - const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); - const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); - return Math.sqrt(dx * dx + dy * dy); -} diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index a6b32e81b160f..fa93aba98e396 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -15,7 +15,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition'; import { HoverStartMode, HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { ContentHoverController, ResizableContentHoverWidget } from 'vs/editor/contrib/hover/browser/contentHover'; +import { ContentHoverController, ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/contentHover'; import { MarginHoverWidget } from 'vs/editor/contrib/hover/browser/marginHover'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -108,7 +108,7 @@ export class ModesHoverController implements IEditorContribution { const target = mouseEvent.target; - if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { + if (target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { this._hoverClicked = true; // mouse down on top of content hover widget return; @@ -146,7 +146,7 @@ export class ModesHoverController implements IEditorContribution { return; } - if (this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID) { + if (this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID) { // mouse moved on top of content hover widget return; } @@ -157,7 +157,7 @@ export class ModesHoverController implements IEditorContribution { } if ( - !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableContentHoverWidget.ID + !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ResizableHoverWidget.ID && this._contentWidget?.isColorPickerVisible() ) { // though the hover is not sticky, the color picker needs to. diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 5187e87855660..797582521d66a 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -4,65 +4,50 @@ *--------------------------------------------------------------------------------------------*/ import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -import { ResourceMap } from 'vs/base/common/map'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; 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 * as dom from 'vs/base/browser/dom'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { clamp } from 'vs/base/common/numbers'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import * as dom from 'vs/base/browser/dom'; - -export interface IResizableWidget extends IDisposable { - - /** - * This method returns a boolean indicating whether the widget is currently resizing. - */ - isResizing(): boolean; - - /** - * Abstract method called when the resizable element is resizing. Should be used to define the new size of the children of the resizable element. - * @param dimension The new dimension of the resizable element. - */ - resize(dimension: dom.Dimension): void; - - /** - * Method which returns the persisted size the resizable widget. It calls the findSize method of the persisting mechanism (whether single or multiple size persisting mechanism). - */ - findPersistedSize(): dom.Dimension | undefined; - - /** - * Method which is called first in the onDidWillResize call of the resizable element. By default it returns nothing. - */ - beforeOnDidWillResize(): void; +import { clamp } from 'vs/base/common/numbers'; +import { ResourceMap } from 'vs/base/common/map'; +import { IPosition } from 'vs/editor/common/core/position'; - /** - * Method which is called last in the onDidResize call of the resizable element. By default it returns nothing. - */ - afterOnDidResize(): void; +export abstract class ResizableContentWidget extends Disposable implements IContentWidget { - /** - * Method which disposes the resizable widget. - */ - dispose(): void; -} + allowEditorOverflow?: boolean | undefined; + suppressMouseDown?: boolean | undefined; -export abstract class ResizableWidget implements IResizableWidget { + protected readonly _contentNode: HTMLDivElement; + protected readonly _resizableNode = this._register(new ResizableHTMLElement()); - public readonly element: ResizableHTMLElement; + private _contentPosition: IContentWidgetPosition | null = null; protected readonly persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; - private readonly disposables = new DisposableStore(); private resizing: boolean = false; constructor( - readonly editor: ICodeEditor, + initalSize: dom.IDimension = new dom.Dimension(100, 100), private readonly persistingOptions: IPersistingOptions, + protected readonly editor: ICodeEditor ) { - - this.element = this.disposables.add(new ResizableHTMLElement()); - this.element.minSize = new dom.Dimension(10, 24); - + super(); + this._contentNode = document.createElement('div'); + this._contentNode.style.width = `${initalSize.width}px`; + this._contentNode.style.height = `${initalSize.height}px`; + this._resizableNode.domNode.appendChild(this._contentNode); + this._resizableNode.minSize = new dom.Dimension(10, 10); + this._resizableNode.enableSashes(true, true, true, true); + this._resizableNode.layout(initalSize.height, initalSize.width); + this._register(this._resizableNode.onDidResize(e => { + this._contentNode.style.width = `${e.dimension.width}px`; + this._contentNode.style.height = `${e.dimension.height}px`; + if (e.done) { + this.resizing = false; + } + })); + this._register(this._resizableNode.onDidWillResize(() => { + this.resizing = true; + })); if (this.persistingOptions instanceof SingleSizePersistingOptions) { this.persistingMechanism = new SingleSizePersistingMechanism(this, this.editor, this.persistingOptions); } else if (this.persistingOptions instanceof MultipleSizePersistingOptions) { @@ -70,120 +55,52 @@ export abstract class ResizableWidget implements IResizableWidget { } else { throw new Error('Please specify a valid persisting mechanism'); } - - this.disposables.add(this.element.onDidWillResize(() => { - this.resizing = true; - })); - this.disposables.add(this.element.onDidResize((e) => { - if (e.done) { - this.resizing = false; - } - })); } - abstract resize(dimension: dom.Dimension): void; + abstract getId(): string; - isResizing() { - return this.resizing; + getDomNode(): HTMLElement { + console.log('Inside of getDomNode of ExampleResizableContentWidget : ', this._resizableNode.domNode); + return this._resizableNode.domNode; } - findPersistedSize(): dom.Dimension | undefined { - return this.persistingMechanism.findSize(); + getPosition(): IContentWidgetPosition | null { + console.log('Inside of getPosition, this._contentPosition : ', this._contentPosition); + return this._contentPosition; } - beforeOnDidWillResize() { - return; + setPosition(value: IContentWidgetPosition | null): void { + console.log('Inside of setPosition, value : ', value); + // TODO: compute boxed above/below if applicable + this._contentPosition = value; } - afterOnDidResize() { - return; - } + // abstract beforeRender?(): IDimension | null; - dispose(): void { - this.disposables.dispose(); + afterRender(position: ContentWidgetPositionPreference | null): void { + // TODO: set max sizes that were computed above } -} - -export interface IResizableContentWidget extends IContentWidget { - - /** - * Abstract method which returns the ID of the content widget - */ - getId(): string; - - /** - * Method which returns the dom node of the resizable element of the resizable widget passed into the constructor - */ - getDomNode(): HTMLElement; - - /** - * Returns the position of the content widget. - */ - getPosition(): IContentWidgetPosition | null; - - /** - * Method which sets the position of the content widget. - */ - set position(position: IPosition | null); - - /** - * Method which sets the secondary position of the content widget. - */ - set secondaryPosition(position: IPosition | null); - - /** - * Method which sets the preferred position of the content widget. - */ - set preference(preference: ContentWidgetPositionPreference[]); - /** - * Method which sets the position affinity of the content widget. - */ - set positionAffinity(affinity: PositionAffinity | undefined); -} - -export abstract class ResizableContentWidget implements IResizableContentWidget { - - private _position: IPosition | null = null; - private _secondaryPosition: IPosition | null = null; - private _preference: ContentWidgetPositionPreference[] = []; - private _positionAffinity: PositionAffinity | undefined = undefined; - - constructor( - private readonly resizableWidget: ResizableWidget - ) { } - - // Method is to abstract because generally we return a static ID - abstract getId(): string; - - getDomNode(): HTMLElement { - return this.resizableWidget.element.domNode; - } + abstract resize(dimension: dom.Dimension): void; - getPosition(): IContentWidgetPosition | null { - const contentWidgetPosition = { - position: this._position, - secondaryPosition: this._secondaryPosition, - preference: (this._preference), - positionAffinity: this._positionAffinity - }; - return contentWidgetPosition; + isResizing() { + return this.resizing; } - set position(position: IPosition | null) { - this._position = position; + findPersistedSize(): dom.Dimension | undefined { + return this.persistingMechanism.findSize(); } - set secondaryPosition(position: IPosition | null) { - this._secondaryPosition = position; + beforeOnDidWillResize() { + return; } - set preference(preference: ContentWidgetPositionPreference[]) { - this._preference = preference; + afterOnDidResize() { + return; } - set positionAffinity(affinity: PositionAffinity | undefined) { - this._positionAffinity = affinity; + get resizableNode(): ResizableHTMLElement { + return this._resizableNode; } } @@ -228,7 +145,7 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly disposables = new DisposableStore(); constructor( - private readonly resizableWidget: ResizableWidget, + private readonly resizableWidget: ResizableContentWidget, private readonly editor: ICodeEditor, private readonly persistingOptions: SingleSizePersistingOptions ) { @@ -236,11 +153,11 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); let state: ResizeState | undefined; - this.disposables.add(this.resizableWidget.element.onDidWillResize(() => { + this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { this.resizableWidget.beforeOnDidWillResize(); - state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.element.size); + state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.resizableNode.size); })); - this.disposables.add(this.resizableWidget.element.onDidResize(e => { + this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; @@ -253,7 +170,7 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { 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.resizableWidget.element.size; + let { width, height } = this.resizableWidget.resizableNode.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; } @@ -291,7 +208,7 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { private _position: IPosition | null = null; constructor( - private readonly resizableWidget: ResizableWidget, + private readonly resizableWidget: ResizableContentWidget, public readonly editor: ICodeEditor ) { this.disposables.add(this.editor.onDidChangeModelContent((e) => { @@ -321,10 +238,10 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } this.persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); - this.disposables.add(this.resizableWidget.element.onDidWillResize(() => { + this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { this.resizableWidget.beforeOnDidWillResize(); })); - this.disposables.add(this.resizableWidget.element.onDidResize(e => { + this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { const height = e.dimension.height; const width = e.dimension.width; this.resizableWidget.resize(new dom.Dimension(width, height)); From 9846e042cee9fead32200dce3df24b4b521a259a Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Wed, 24 May 2023 14:32:46 +0200 Subject: [PATCH 49/72] cleaning the code --- src/vs/base/browser/ui/resizable/resizable.ts | 4 -- .../contrib/hover/browser/contentHover.ts | 71 ++++++------------- .../hover/browser/resizableContentWidget.ts | 11 ++- 3 files changed, 26 insertions(+), 60 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index d71281f3dc135..9bd5f4ff54219 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -164,10 +164,6 @@ export class ResizableHTMLElement { return this._size; } - set size(size: Dimension) { - this._size = size; - } - set maxSize(value: Dimension) { this._maxSize = value; } diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index f492a92dfc694..64f1db89f0aaf 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -185,9 +185,6 @@ export class ContentHoverController extends Disposable { } private _setCurrentResult(hoverResult: HoverResult | null): void { - console.log('Inside of _setCurrentResult'); - console.log('hoverResult: ', hoverResult); - if (this._currentResult === hoverResult) { // avoid updating the DOM to avoid resetting the user selection return; @@ -221,6 +218,7 @@ export class ContentHoverController extends Disposable { return this._widget.isVisible; } + // TODO: check if this is needed? public containsNode(node: Node | null | undefined): boolean { return (node ? this._widget.getDomNode().contains(node) : false); } @@ -258,9 +256,6 @@ export class ContentHoverController extends Disposable { } private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void { - - console.log('Inside of _renderMessages'); - const { showAtPosition, showAtSecondaryPosition, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages); const disposables = new DisposableStore(); @@ -301,7 +296,6 @@ export class ContentHoverController extends Disposable { })); } - console.log('Right before the showAt function of the _renderMessages function'); this._widget.showAt(fragment, new ContentHoverVisibleData( colorPicker, showAtPosition, @@ -465,11 +459,11 @@ export class ResizableHoverWidget extends ResizableContentWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; private disposableStore = new DisposableStore(); - private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); private visibleData: ContentHoverVisibleData | null = null; private renderingAbove: ContentWidgetPositionPreference | null = null; private visible: boolean = false; + private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); private readonly focusTracker: dom.IFocusTracker; @@ -480,18 +474,33 @@ export class ResizableHoverWidget extends ResizableContentWidget { private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; + public get position(): Position | null { + return this.visibleData?.showAtPosition ?? null; + } + + public get isColorPickerVisible(): boolean { + return Boolean(this.visibleData?.colorPicker); + } + + public get isVisibleFromKeyboard(): boolean { + return (this.visibleData?.source === HoverStartSource.Keyboard); + } + + public get isVisible(): boolean { + return this.hoverVisibleKey.get() ?? false; + } + constructor( editor: ICodeEditor, @IContextKeyService private readonly contextKeyService: IContextKeyService ) { - console.log('Inside of the constructor of the ExampleResizableHoverWidget'); - const initalSize = new dom.Dimension(10, 10); const persistingOptions = new MultipleSizePersistingOptions(); super(initalSize, persistingOptions, editor); this.resizableNode.domNode.style.position = 'absolute'; this.resizableNode.domNode.style.zIndex = '50'; dom.append(this.resizableNode.domNode, this.hoverWidget.containerDomNode); + this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { @@ -509,36 +518,20 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._layout(); } - public get position(): Position | null { - return this.visibleData?.showAtPosition ?? null; - } - - public get isColorPickerVisible(): boolean { - return Boolean(this.visibleData?.colorPicker); - } - - public get isVisibleFromKeyboard(): boolean { - return (this.visibleData?.source === HoverStartSource.Keyboard); - } - - public get isVisible(): boolean { - return this.hoverVisibleKey.get() ?? false; - } - public getId(): string { return ResizableHoverWidget.ID; } public resize(size: dom.Dimension) { - console.log('Inside of the resize function'); - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; this.hoverWidget.containerDomNode.style.width = width; this.hoverWidget.contentsDomNode.style.width = width; + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this.hoverWidget.containerDomNode.style.height = height + 'px'; const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); @@ -549,12 +542,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this.hoverWidget.containerDomNode.style.height = height + 'px'; this.hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; } else { - const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this.hoverWidget.containerDomNode.style.height = height + 'px'; this.hoverWidget.contentsDomNode.style.height = height + 'px'; } @@ -602,7 +591,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public findMaximumRenderingHeight(): number | undefined { - const availableSpace = this.findAvailableSpaceVertically(); if (!availableSpace) { return; @@ -685,33 +673,22 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - console.log('Inside of the showAt function'); - if (!this.editor || !this.editor.hasModel()) { return; } if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { this.persistingMechanism.position = visibleData.showAtPosition; } + this._setVisibleData(visibleData); this._position = visibleData.showAtPosition; this._secondaryPosition = visibleData.showAtSecondaryPosition; this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - - // --- - // Fixing the position data const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; this.setPosition(widgetPosition); - // --- - - this._setVisibleData(visibleData); - - console.log('this.visible : ', this.visible); if (!this.visible) { - console.log('right before adding the content widget'); this.editor.addContentWidget(this); } - this.hoverWidget.contentsDomNode.textContent = ''; this.hoverWidget.contentsDomNode.appendChild(node); this.hoverWidget.contentsDomNode.style.paddingBottom = ''; @@ -719,7 +696,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { let height; const persistedSize = this.findPersistedSize(); - console.log('persistedSize : ', persistedSize); // If there is no persisted size, then normally render if (!persistedSize) { @@ -799,7 +775,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public hide(): void { - console.log('Inside of the hide function'); this.visible = false; this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); @@ -822,8 +797,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { public onContentsChanged(): void { - console.log('Inside of onContentsChanged'); - const persistedSize = this.findPersistedSize(); const containerDomNode = this.hoverWidget.containerDomNode; const contentsDomNode = this.hoverWidget.contentsDomNode; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 797582521d66a..7c88cc0b2187f 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -26,18 +26,18 @@ export abstract class ResizableContentWidget extends Disposable implements ICont private resizing: boolean = false; constructor( - initalSize: dom.IDimension = new dom.Dimension(100, 100), + initialSize: dom.IDimension = new dom.Dimension(100, 100), private readonly persistingOptions: IPersistingOptions, protected readonly editor: ICodeEditor ) { super(); this._contentNode = document.createElement('div'); - this._contentNode.style.width = `${initalSize.width}px`; - this._contentNode.style.height = `${initalSize.height}px`; + this._contentNode.style.width = `${initialSize.width}px`; + this._contentNode.style.height = `${initialSize.height}px`; this._resizableNode.domNode.appendChild(this._contentNode); this._resizableNode.minSize = new dom.Dimension(10, 10); this._resizableNode.enableSashes(true, true, true, true); - this._resizableNode.layout(initalSize.height, initalSize.width); + this._resizableNode.layout(initialSize.height, initialSize.width); this._register(this._resizableNode.onDidResize(e => { this._contentNode.style.width = `${e.dimension.width}px`; this._contentNode.style.height = `${e.dimension.height}px`; @@ -60,17 +60,14 @@ export abstract class ResizableContentWidget extends Disposable implements ICont abstract getId(): string; getDomNode(): HTMLElement { - console.log('Inside of getDomNode of ExampleResizableContentWidget : ', this._resizableNode.domNode); return this._resizableNode.domNode; } getPosition(): IContentWidgetPosition | null { - console.log('Inside of getPosition, this._contentPosition : ', this._contentPosition); return this._contentPosition; } setPosition(value: IContentWidgetPosition | null): void { - console.log('Inside of setPosition, value : ', value); // TODO: compute boxed above/below if applicable this._contentPosition = value; } From 0e15526c7aaa2f34427cb19e69ebdddd12451d44 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 11:57:00 +0200 Subject: [PATCH 50/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 206 +++++++++--------- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index b06305e9e6ee0..dfe55f220c96e 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -218,7 +218,6 @@ export class ContentHoverController extends Disposable { return this._widget.isVisible; } - // TODO: check if this is needed? public containsNode(node: Node | null | undefined): boolean { return (node ? this._widget.getDomNode().contains(node) : false); } @@ -458,16 +457,16 @@ export class ResizableHoverWidget extends ResizableContentWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; - private disposableStore = new DisposableStore(); - private visibleData: ContentHoverVisibleData | null = null; - private renderingAbove: ContentWidgetPositionPreference | null = null; - private visible: boolean = false; + private _disposableStore = new DisposableStore(); + private _visibleData: ContentHoverVisibleData | null = null; + private _renderingAbove: ContentWidgetPositionPreference | null = null; + private _visible: boolean = false; - private readonly hoverWidget: HoverWidget = this.disposableStore.add(new HoverWidget()); - private readonly hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); - private readonly hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); - private readonly focusTracker: dom.IFocusTracker; - private readonly horizontalScrollingBy: number = 30; + private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); + private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); + private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); + private readonly _focusTracker: dom.IFocusTracker; + private readonly _horizontalScrollingBy: number = 30; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; @@ -475,19 +474,19 @@ export class ResizableHoverWidget extends ResizableContentWidget { private _positionAffinity: PositionAffinity | undefined = undefined; public get position(): Position | null { - return this.visibleData?.showAtPosition ?? null; + return this._visibleData?.showAtPosition ?? null; } public get isColorPickerVisible(): boolean { - return Boolean(this.visibleData?.colorPicker); + return Boolean(this._visibleData?.colorPicker); } public get isVisibleFromKeyboard(): boolean { - return (this.visibleData?.source === HoverStartSource.Keyboard); + return (this._visibleData?.source === HoverStartSource.Keyboard); } public get isVisible(): boolean { - return this.hoverVisibleKey.get() ?? false; + return this._hoverVisibleKey.get() ?? false; } constructor( @@ -499,20 +498,20 @@ export class ResizableHoverWidget extends ResizableContentWidget { super(initalSize, persistingOptions, editor); this.resizableNode.domNode.style.position = 'absolute'; this.resizableNode.domNode.style.zIndex = '50'; - dom.append(this.resizableNode.domNode, this.hoverWidget.containerDomNode); + dom.append(this.resizableNode.domNode, this._hoverWidget.containerDomNode); - this.focusTracker = this.disposableStore.add(dom.trackFocus(this.hoverWidget.contentsDomNode)); - this.disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); - this.disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + this._focusTracker = this._disposableStore.add(dom.trackFocus(this._hoverWidget.contentsDomNode)); + this._disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); + this._disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); - this.disposableStore.add(this.focusTracker.onDidFocus(() => { - this.hoverFocusedKey.set(true); + this._disposableStore.add(this._focusTracker.onDidFocus(() => { + this._hoverFocusedKey.set(true); })); - this.disposableStore.add(this.focusTracker.onDidBlur(() => { - this.hoverFocusedKey.set(false); + this._disposableStore.add(this._focusTracker.onDidBlur(() => { + this._hoverFocusedKey.set(false); })); this._setVisibleData(null); this._layout(); @@ -524,27 +523,27 @@ export class ResizableHoverWidget extends ResizableContentWidget { public resize(size: dom.Dimension) { - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.hoverWidget.containerDomNode.style.width = width; - this.hoverWidget.contentsDomNode.style.width = width; + this._hoverWidget.containerDomNode.style.width = width; + this._hoverWidget.contentsDomNode.style.width = width; const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this.hoverWidget.containerDomNode.style.height = height + 'px'; + this._hoverWidget.containerDomNode.style.height = height + 'px'; - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this._hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this._hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - this.hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; + this._hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; } else { - this.hoverWidget.contentsDomNode.style.height = height + 'px'; + this._hoverWidget.contentsDomNode.style.height = height + 'px'; } const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; @@ -564,20 +563,20 @@ export class ResizableHoverWidget extends ResizableContentWidget { return; } this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); - this.hoverWidget.scrollbar.scanDomNode(); + this._hoverWidget.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this); } public findAvailableSpaceVertically(): number | undefined { - if (!this.editor || !this.editor.hasModel() || !this.visibleData?.showAtPosition) { + if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(this.visibleData.showAtPosition); + const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { availableSpace = editorBox.top + mouseBox.top - 30; } else { const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; @@ -596,10 +595,10 @@ export class ResizableHoverWidget extends ResizableContentWidget { return; } let divMaxHeight = 3 * SASH_WIDTH_MINUS_BORDER; - for (const childHtmlElement of this.hoverWidget.contentsDomNode.children) { + for (const childHtmlElement of this._hoverWidget.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } - if (this.hoverWidget.contentsDomNode.clientWidth < this.hoverWidget.contentsDomNode.scrollWidth) { + if (this._hoverWidget.contentsDomNode.clientWidth < this._hoverWidget.contentsDomNode.scrollWidth) { divMaxHeight += SCROLLBAR_WIDTH; } return Math.min(availableSpace, divMaxHeight); @@ -613,62 +612,62 @@ export class ResizableHoverWidget extends ResizableContentWidget { const widthOfEditor = editorBox.width; const leftOfEditor = editorBox.left; const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; - const leftOfContainer = this.hoverWidget.containerDomNode.offsetLeft; + const leftOfContainer = this._hoverWidget.containerDomNode.offsetLeft; return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } public override dispose(): void { this.editor.removeContentWidget(this); - if (this.visibleData) { - this.visibleData.disposables.dispose(); + if (this._visibleData) { + this._visibleData.disposables.dispose(); } super.dispose(); } public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this.visibleData) { + if (!this._visibleData) { return false; } - if (typeof this.visibleData.initialMousePosX === 'undefined' || typeof this.visibleData.initialMousePosY === 'undefined') { - this.visibleData.initialMousePosX = posx; - this.visibleData.initialMousePosY = posy; + if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { + this._visibleData.initialMousePosX = posx; + this._visibleData.initialMousePosY = posy; return false; } const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); - if (typeof this.visibleData.closestMouseDistance === 'undefined') { - this.visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this.visibleData.initialMousePosX, this.visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (typeof this._visibleData.closestMouseDistance === 'undefined') { + this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (!distance || !this.visibleData.closestMouseDistance || distance > this.visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } - this.visibleData.closestMouseDistance = Math.min(this.visibleData.closestMouseDistance, distance); + this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); return true; } private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { - if (this.visibleData) { - this.visibleData.disposables.dispose(); + if (this._visibleData) { + this._visibleData.disposables.dispose(); } - this.visibleData = visibleData; - this.hoverVisibleKey.set(!!this.visibleData); - this.hoverWidget.containerDomNode.classList.toggle('hidden', !this.visibleData); + this._visibleData = visibleData; + this._hoverVisibleKey.set(!!this._visibleData); + this._hoverWidget.containerDomNode.classList.toggle('hidden', !this._visibleData); } private _layout(): void { const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; - this.hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this.hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this._hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; + this._hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + this._hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this.hoverWidget.contentsDomNode.getElementsByClassName('code')); + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hoverWidget.contentsDomNode.getElementsByClassName('code')); codeClasses.forEach(node => this.editor.applyFontInfo(node)); } @@ -686,12 +685,12 @@ export class ResizableHoverWidget extends ResizableContentWidget { const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; this.setPosition(widgetPosition); - if (!this.visible) { + if (!this._visible) { this.editor.addContentWidget(this); } - this.hoverWidget.contentsDomNode.textContent = ''; - this.hoverWidget.contentsDomNode.appendChild(node); - this.hoverWidget.contentsDomNode.style.paddingBottom = ''; + this._hoverWidget.contentsDomNode.textContent = ''; + this._hoverWidget.contentsDomNode.appendChild(node); + this._hoverWidget.contentsDomNode.style.paddingBottom = ''; this._updateFont(); let height; @@ -699,18 +698,19 @@ export class ResizableHoverWidget extends ResizableContentWidget { // If there is no persisted size, then normally render if (!persistedSize) { - this.hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - this.hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); + // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this.editor.render(); - height = this.hoverWidget.containerDomNode.clientHeight + 6; + height = this._hoverWidget.containerDomNode.clientHeight + 6; } // When there is a persisted size then do not use a maximum height or width else { - this.hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this.hoverWidget.contentsDomNode.style.maxWidth = 'none'; + this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; height = persistedSize.height; } @@ -743,18 +743,18 @@ export class ResizableHoverWidget extends ResizableContentWidget { // Determining whether we should render above or not ideally if (this.editor.getOption(EditorOption.hover).above) { - this.renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; } else { - this.renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } - if (this.renderingAbove === ContentWidgetPositionPreference.ABOVE) { + if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { this.resizableNode.enableSashes(true, true, false, false); } else { this.resizableNode.enableSashes(false, true, true, false); } - this._preference = [this.renderingAbove]; + this._preference = [this._renderingAbove]; // -- Fixing the position widgetPosition.preference = this._preference; @@ -768,20 +768,20 @@ export class ResizableHoverWidget extends ResizableContentWidget { } if (visibleData.stoleFocus) { - this.hoverWidget.containerDomNode.focus(); + this._hoverWidget.containerDomNode.focus(); } visibleData.colorPicker?.layout(); - this.visible = true; + this._visible = true; } public hide(): void { - this.visible = false; + this._visible = false; this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); this.resizableNode.clearSashHoverState(); this.editor.removeContentWidget(this); - if (this.visibleData) { - const stoleFocus = this.visibleData.stoleFocus; + if (this._visibleData) { + const stoleFocus = this._visibleData.stoleFocus; this._setVisibleData(null); this._hoverFocusedKey.set(false); this.editor.layoutContentWidget(this); @@ -793,14 +793,14 @@ export class ResizableHoverWidget extends ResizableContentWidget { private _layoutContentWidget(): void { this.editor.layoutContentWidget(this); - this.hoverWidget.onContentsChanged(); + this._hoverWidget.onContentsChanged(); } public onContentsChanged(): void { const persistedSize = this.findPersistedSize(); - const containerDomNode = this.hoverWidget.containerDomNode; - const contentsDomNode = this.hoverWidget.contentsDomNode; + const containerDomNode = this._hoverWidget.containerDomNode; + const contentsDomNode = this._hoverWidget.contentsDomNode; // Suppose a persisted size is defined if (persistedSize) { @@ -834,12 +834,12 @@ export class ResizableHoverWidget extends ResizableContentWidget { containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - const scrollDimensions = this.hoverWidget.scrollbar.getScrollDimensions(); + const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { - const extraBottomPadding = `${this.hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this.hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this.hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (this._hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { + this._hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } const maxRenderingHeight = this.findMaximumRenderingHeight(); if (!maxRenderingHeight) { @@ -870,53 +870,53 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public clear(): void { - this.hoverWidget.contentsDomNode.textContent = ''; + this._hoverWidget.contentsDomNode.textContent = ''; } public focus(): void { - this.hoverWidget.containerDomNode.focus(); + this._hoverWidget.containerDomNode.focus(); } public scrollUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); } public scrollDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); } public scrollLeft(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this.horizontalScrollingBy }); + const scrollLeft = this._hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); } public scrollRight(): void { - const scrollLeft = this.hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this.hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this.horizontalScrollingBy }); + const scrollLeft = this._hoverWidget.scrollbar.getScrollPosition().scrollLeft; + this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); } public pageUp(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); + const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this._hoverWidget.scrollbar.getScrollDimensions().height; + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); } public pageDown(): void { - const scrollTop = this.hoverWidget.scrollbar.getScrollPosition().scrollTop; - const scrollHeight = this.hoverWidget.scrollbar.getScrollDimensions().height; - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); + const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; + const scrollHeight = this._hoverWidget.scrollbar.getScrollDimensions().height; + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); } public goToTop(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: 0 }); } public goToBottom(): void { - this.hoverWidget.scrollbar.setScrollPosition({ scrollTop: this.hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: this._hoverWidget.scrollbar.getScrollDimensions().scrollHeight }); } public escape(): void { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 031d218e31d03..844e8ae4b87dd 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -15,7 +15,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ILanguageService } from 'vs/editor/common/languages/language'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition'; import { HoverStartMode, HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; -import { ContentHoverController, ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/contentHover'; +import { ResizableHoverWidget, ContentHoverController } from 'vs/editor/contrib/hover/browser/contentHover'; import { MarginHoverWidget } from 'vs/editor/contrib/hover/browser/marginHover'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; From bcd704ac6d816beaa58420a984626be2729a14ac Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 12:39:08 +0200 Subject: [PATCH 51/72] placing the rendering preference code into the generic resizable content widget class, the container dom node content seems to disappear sometimes --- .../contrib/hover/browser/contentHover.ts | 142 ++++++------------ src/vs/editor/contrib/hover/browser/hover.ts | 2 +- .../hover/browser/resizableContentWidget.ts | 81 ++++++++-- 3 files changed, 114 insertions(+), 111 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index dfe55f220c96e..dad500113de4e 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -11,7 +11,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; -import { IPosition, Position } from 'vs/editor/common/core/position'; +import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { IModelDecoration, PositionAffinity } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; @@ -81,7 +81,7 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { - if (this._widget.isResizing()) { + if (this._widget.resizing) { return true; } const anchorCandidates: HoverAnchor[] = []; @@ -458,8 +458,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; private _disposableStore = new DisposableStore(); - private _visibleData: ContentHoverVisibleData | null = null; - private _renderingAbove: ContentWidgetPositionPreference | null = null; + private _visibleData: ContentHoverVisibleData | undefined; + private _renderingAbove: ContentWidgetPositionPreference | undefined; private _visible: boolean = false; private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); @@ -468,13 +468,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { private readonly _focusTracker: dom.IFocusTracker; private readonly _horizontalScrollingBy: number = 30; - private _position: IPosition | null = null; - private _secondaryPosition: IPosition | null = null; - private _preference: ContentWidgetPositionPreference[] = []; - private _positionAffinity: PositionAffinity | undefined = undefined; - - public get position(): Position | null { - return this._visibleData?.showAtPosition ?? null; + public get position(): Position | undefined { + return this._visibleData?.showAtPosition; } public get isColorPickerVisible(): boolean { @@ -501,8 +496,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { dom.append(this.resizableNode.domNode, this._hoverWidget.containerDomNode); this._focusTracker = this._disposableStore.add(dom.trackFocus(this._hoverWidget.contentsDomNode)); - this._disposableStore.add(this.editor.onDidLayoutChange(() => this._layout())); - this._disposableStore.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + this._disposableStore.add(this._editor.onDidLayoutChange(() => this._layout())); + this._disposableStore.add(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } @@ -513,7 +508,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._disposableStore.add(this._focusTracker.onDidBlur(() => { this._hoverFocusedKey.set(false); })); - this._setVisibleData(null); + this._setVisibleData(undefined); this._layout(); } @@ -564,15 +559,15 @@ export class ResizableHoverWidget extends ResizableContentWidget { } this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); this._hoverWidget.scrollbar.scanDomNode(); - this.editor.layoutContentWidget(this); + this._editor.layoutContentWidget(this); } public findAvailableSpaceVertically(): number | undefined { - if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { + if (!this._editor || !this._editor.hasModel() || !this._visibleData?.showAtPosition) { return; } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); + const editorBox = dom.getDomNodePagePosition(this._editor.getDomNode()); + const mouseBox = this._editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; @@ -605,19 +600,19 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public findMaximumRenderingWidth(): number | undefined { - if (!this.editor || !this.editor.hasModel()) { + if (!this._editor || !this._editor.hasModel()) { return; } - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); + const editorBox = dom.getDomNodePagePosition(this._editor.getDomNode()); const widthOfEditor = editorBox.width; const leftOfEditor = editorBox.left; - const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; + const glyphMarginWidth = this._editor.getLayoutInfo().glyphMarginWidth; const leftOfContainer = this._hoverWidget.containerDomNode.offsetLeft; return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } public override dispose(): void { - this.editor.removeContentWidget(this); + this._editor.removeContentWidget(this); if (this._visibleData) { this._visibleData.disposables.dispose(); } @@ -647,7 +642,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { return true; } - private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { + private _setVisibleData(visibleData: ContentHoverVisibleData | undefined): void { if (this._visibleData) { this._visibleData.disposables.dispose(); } @@ -657,36 +652,36 @@ export class ResizableHoverWidget extends ResizableContentWidget { } private _layout(): void { - const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); + const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); + const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); this._hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; this._hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; this._hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hoverWidget.contentsDomNode.getElementsByClassName('code')); - codeClasses.forEach(node => this.editor.applyFontInfo(node)); + codeClasses.forEach(node => this._editor.applyFontInfo(node)); } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - if (!this.editor || !this.editor.hasModel()) { + if (!this._editor || !this._editor.hasModel()) { return; } - if (this.persistingMechanism instanceof MultipleSizePersistingMechanism) { - this.persistingMechanism.position = visibleData.showAtPosition; + if (this._persistingMechanism instanceof MultipleSizePersistingMechanism) { + this._persistingMechanism.position = visibleData.showAtPosition; } this._setVisibleData(visibleData); - this._position = visibleData.showAtPosition; - this._secondaryPosition = visibleData.showAtSecondaryPosition; - this._positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - const widgetPosition: IContentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, positionAffinity: this._positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; + const position = visibleData.showAtPosition; + const secondaryPosition = visibleData.showAtSecondaryPosition; + const positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; + const widgetPosition: IContentWidgetPosition = { position: position, secondaryPosition: secondaryPosition, positionAffinity: positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; this.setPosition(widgetPosition); if (!this._visible) { - this.editor.addContentWidget(this); + this._editor.addContentWidget(this); } this._hoverWidget.contentsDomNode.textContent = ''; this._hoverWidget.contentsDomNode.appendChild(node); @@ -698,13 +693,13 @@ export class ResizableHoverWidget extends ResizableContentWidget { // If there is no persisted size, then normally render if (!persistedSize) { - this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; + this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' - this.editor.render(); + this._editor.render(); height = this._hoverWidget.containerDomNode.clientHeight + 6; } // When there is a persisted size then do not use a maximum height or width @@ -713,53 +708,12 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; height = persistedSize.height; } - - // The dimensions of the document in which we are displaying the hover - const bodyBox = dom.getClientArea(document.body); - // Hard-coded in the hover.css file as 1.5em or 24px - const minHeight = 24; - // The full height is already passed in as a parameter - const fullHeight = height; - const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); - const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); - // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height - const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position - const availableSpaceBelow = bodyBox.height - mouseBottom; - // Max height below is the minimum of the available space below and the full height of the widget - const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); - // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor - const availableSpaceAbove = editorBox.top + mouseBox.top - 30; - const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); - // We find the maximum height of the widget possible on the top or on the bottom - const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); - - if (height < minHeight) { - height = minHeight; - } - if (height > maxHeight) { - height = maxHeight; - } - - // Determining whether we should render above or not ideally - if (this.editor.getOption(EditorOption.hover).above) { - this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; - } else { - this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; - } - - if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { - this.resizableNode.enableSashes(true, true, false, false); - } else { - this.resizableNode.enableSashes(false, true, true, false); + this._renderingAbove = this.findRenderingPreference(height, position); + if (!this._renderingAbove) { + return; } - - this._preference = [this._renderingAbove]; - - // -- Fixing the position - widgetPosition.preference = this._preference; + widgetPosition.preference = [this._renderingAbove]; this.setPosition(widgetPosition); - // --- // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor @@ -779,20 +733,20 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._visible = false; this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); this.resizableNode.clearSashHoverState(); - this.editor.removeContentWidget(this); + this._editor.removeContentWidget(this); if (this._visibleData) { const stoleFocus = this._visibleData.stoleFocus; - this._setVisibleData(null); + this._setVisibleData(undefined); this._hoverFocusedKey.set(false); - this.editor.layoutContentWidget(this); + this._editor.layoutContentWidget(this); if (stoleFocus) { - this.editor.focus(); + this._editor.focus(); } } } private _layoutContentWidget(): void { - this.editor.layoutContentWidget(this); + this._editor.layoutContentWidget(this); this._hoverWidget.onContentsChanged(); } @@ -817,8 +771,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; // Added because otherwise the initial size of the hover content is smaller than should be - this.resizableNode.domNode.style.width = this.editor.getLayoutInfo().width + 'px'; - this.resizableNode.domNode.style.height = this.editor.getLayoutInfo().height + 'px'; + this.resizableNode.domNode.style.width = this._editor.getLayoutInfo().width + 'px'; + this.resizableNode.domNode.style.height = this._editor.getLayoutInfo().height + 'px'; this._layoutContentWidget(); // Added otherwise rendered too small horizontally containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; @@ -879,13 +833,13 @@ export class ResizableHoverWidget extends ResizableContentWidget { public scrollUp(): void { const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); + const fontInfo = this._editor.getOption(EditorOption.fontInfo); this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); } public scrollDown(): void { const scrollTop = this._hoverWidget.scrollbar.getScrollPosition().scrollTop; - const fontInfo = this.editor.getOption(EditorOption.fontInfo); + const fontInfo = this._editor.getOption(EditorOption.fontInfo); this._hoverWidget.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); } @@ -920,11 +874,11 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public escape(): void { - this.editor.focus(); + this._editor.focus(); } public clearPersistedSizes(): void { - this.persistingMechanism.clear(); + this._persistingMechanism.clear(); } } diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 844e8ae4b87dd..7c07608280d19 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -222,7 +222,7 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); - if (!this._contentWidget?.widget.isResizing()) { + if (!this._contentWidget?.widget.resizing) { this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 7c88cc0b2187f..4ba34ad4f1843 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -20,15 +20,15 @@ export abstract class ResizableContentWidget extends Disposable implements ICont protected readonly _contentNode: HTMLDivElement; protected readonly _resizableNode = this._register(new ResizableHTMLElement()); + protected readonly _persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; private _contentPosition: IContentWidgetPosition | null = null; - protected readonly persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; - private resizing: boolean = false; + private _resizing: boolean = false; constructor( initialSize: dom.IDimension = new dom.Dimension(100, 100), - private readonly persistingOptions: IPersistingOptions, - protected readonly editor: ICodeEditor + private readonly _persistingOptions: IPersistingOptions, + protected readonly _editor: ICodeEditor ) { super(); this._contentNode = document.createElement('div'); @@ -42,16 +42,16 @@ export abstract class ResizableContentWidget extends Disposable implements ICont this._contentNode.style.width = `${e.dimension.width}px`; this._contentNode.style.height = `${e.dimension.height}px`; if (e.done) { - this.resizing = false; + this._resizing = false; } })); this._register(this._resizableNode.onDidWillResize(() => { - this.resizing = true; + this._resizing = true; })); - if (this.persistingOptions instanceof SingleSizePersistingOptions) { - this.persistingMechanism = new SingleSizePersistingMechanism(this, this.editor, this.persistingOptions); - } else if (this.persistingOptions instanceof MultipleSizePersistingOptions) { - this.persistingMechanism = new MultipleSizePersistingMechanism(this, this.editor); + if (this._persistingOptions instanceof SingleSizePersistingOptions) { + this._persistingMechanism = new SingleSizePersistingMechanism(this, this._editor, this._persistingOptions); + } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { + this._persistingMechanism = new MultipleSizePersistingMechanism(this, this._editor); } else { throw new Error('Please specify a valid persisting mechanism'); } @@ -67,9 +67,58 @@ export abstract class ResizableContentWidget extends Disposable implements ICont return this._contentPosition; } - setPosition(value: IContentWidgetPosition | null): void { - // TODO: compute boxed above/below if applicable - this._contentPosition = value; + findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { + const editorDomNode = this._editor.getDomNode(); + if (!editorDomNode) { + return; + } + let height = widgetHeight; + // The dimensions of the document in which we are displaying the hover + const bodyBox = dom.getClientArea(document.body); + // Hard-coded in the hover.css file as 1.5em or 24px + const minHeight = 24; + // The full height is already passed in as a parameter + const fullHeight = widgetHeight; + const editorBox = dom.getDomNodePagePosition(editorDomNode); + const mouseBox = this._editor.getScrolledVisiblePosition(showAtPosition); + if (!mouseBox) { + return; + } + // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height + const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; + // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position + const availableSpaceBelow = bodyBox.height - mouseBottom; + // Max height below is the minimum of the available space below and the full height of the widget + const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); + // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor + const availableSpaceAbove = editorBox.top + mouseBox.top - 30; + const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); + // We find the maximum height of the widget possible on the top or on the bottom + const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); + + if (widgetHeight < minHeight) { + height = minHeight; + } + if (height > maxHeight) { + height = maxHeight; + } + // Determining whether we should render above or not ideally + let renderingAbove: ContentWidgetPositionPreference; + if (this._editor.getOption(EditorOption.hover).above) { + renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; + } else { + renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; + } + if (renderingAbove === ContentWidgetPositionPreference.ABOVE) { + this.resizableNode.enableSashes(true, true, false, false); + } else { + this.resizableNode.enableSashes(false, true, true, false); + } + return renderingAbove; + } + + setPosition(contentPosition: IContentWidgetPosition | null): void { + this._contentPosition = contentPosition; } // abstract beforeRender?(): IDimension | null; @@ -80,12 +129,12 @@ export abstract class ResizableContentWidget extends Disposable implements ICont abstract resize(dimension: dom.Dimension): void; - isResizing() { - return this.resizing; + get resizing() { + return this._resizing; } findPersistedSize(): dom.Dimension | undefined { - return this.persistingMechanism.findSize(); + return this._persistingMechanism.findSize(); } beforeOnDidWillResize() { From 79096b0388d401e2d07802e45c46a4881db82e76 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 15:33:04 +0200 Subject: [PATCH 52/72] refactoring the code --- .../contrib/hover/browser/contentHover.ts | 103 ++++---- .../hover/browser/resizableContentWidget.ts | 231 +++++++----------- 2 files changed, 138 insertions(+), 196 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index dad500113de4e..ef6d413545510 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -23,7 +23,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { AsyncIterableObject } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { MultipleSizePersistingMechanism, MultipleSizePersistingOptions, ResizableContentWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; +import { MultiplePersistedSizeResizableContentWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; const $ = dom.$; export class ContentHoverController extends Disposable { @@ -67,7 +67,7 @@ export class ContentHoverController extends Disposable { })); this._register(TokenizationRegistry.onDidChange(() => { if (this._widget.position && this._currentResult) { - this._widget.clear(); + this._widget.clearPersistedSizes(); this._setCurrentResult(this._currentResult); // render again } })); @@ -453,14 +453,16 @@ const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; const DELTA_SASH_LENGTH = 4; -export class ResizableHoverWidget extends ResizableContentWidget { +export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentWidget { public static ID = 'editor.contrib.resizableContentHoverWidget'; private _disposableStore = new DisposableStore(); private _visibleData: ContentHoverVisibleData | undefined; private _renderingAbove: ContentWidgetPositionPreference | undefined; + // TODO: change so as to use directly the _hoverVisibleKey instead of the boolean here private _visible: boolean = false; + // TODO: above private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); @@ -468,10 +470,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { private readonly _focusTracker: dom.IFocusTracker; private readonly _horizontalScrollingBy: number = 30; - public get position(): Position | undefined { - return this._visibleData?.showAtPosition; - } - public get isColorPickerVisible(): boolean { return Boolean(this._visibleData?.colorPicker); } @@ -488,10 +486,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { editor: ICodeEditor, @IContextKeyService private readonly contextKeyService: IContextKeyService ) { - const initalSize = new dom.Dimension(10, 10); - const persistingOptions = new MultipleSizePersistingOptions(); - super(initalSize, persistingOptions, editor); - this.resizableNode.domNode.style.position = 'absolute'; + super(editor); this.resizableNode.domNode.style.zIndex = '50'; dom.append(this.resizableNode.domNode, this._hoverWidget.containerDomNode); @@ -520,7 +515,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; - const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; this._hoverWidget.containerDomNode.style.width = width; this._hoverWidget.contentsDomNode.style.width = width; @@ -528,8 +522,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._hoverWidget.containerDomNode.style.height = height + 'px'; const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - + const hasHorizontalScrollbar = scrollDimensions.scrollWidth > scrollDimensions.width; if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; @@ -540,7 +533,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { } else { this._hoverWidget.contentsDomNode.style.height = height + 'px'; } - const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; this.resizableNode.northSash.el.style.width = horizontalSashLength; this.resizableNode.southSash.el.style.width = horizontalSashLength; @@ -554,6 +546,8 @@ export class ResizableHoverWidget extends ResizableContentWidget { const maxRenderingWidth = this.findMaximumRenderingWidth(); const maxRenderingHeight = this.findMaximumRenderingHeight(); + console.log('maxRenderingWidth : ', maxRenderingWidth); + console.log('maxRenderingHeight : ', maxRenderingHeight); if (!maxRenderingWidth || !maxRenderingHeight) { return; } @@ -570,7 +564,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { const mouseBox = this._editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; - if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { availableSpace = editorBox.top + mouseBox.top - 30; } else { @@ -612,11 +605,9 @@ export class ResizableHoverWidget extends ResizableContentWidget { } public override dispose(): void { - this._editor.removeContentWidget(this); - if (this._visibleData) { - this._visibleData.disposables.dispose(); - } super.dispose(); + this._visibleData?.disposables.dispose(); + this._editor.removeContentWidget(this); } public isMouseGettingCloser(posx: number, posy: number): boolean { @@ -634,6 +625,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + // TODO: do we need the following? if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; @@ -670,45 +662,24 @@ export class ResizableHoverWidget extends ResizableContentWidget { if (!this._editor || !this._editor.hasModel()) { return; } - if (this._persistingMechanism instanceof MultipleSizePersistingMechanism) { - this._persistingMechanism.position = visibleData.showAtPosition; - } + this._position = visibleData.showAtPosition; this._setVisibleData(visibleData); - const position = visibleData.showAtPosition; - const secondaryPosition = visibleData.showAtSecondaryPosition; - const positionAffinity = visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; - const widgetPosition: IContentWidgetPosition = { position: position, secondaryPosition: secondaryPosition, positionAffinity: positionAffinity, preference: [ContentWidgetPositionPreference.ABOVE] }; + const widgetPosition: IContentWidgetPosition = { + position: visibleData.showAtPosition, + secondaryPosition: visibleData.showAtSecondaryPosition, + positionAffinity: visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, + preference: [ContentWidgetPositionPreference.ABOVE] + }; this.setPosition(widgetPosition); - if (!this._visible) { this._editor.addContentWidget(this); } + this._hoverWidget.contentsDomNode.style.paddingBottom = ''; this._hoverWidget.contentsDomNode.textContent = ''; this._hoverWidget.contentsDomNode.appendChild(node); - this._hoverWidget.contentsDomNode.style.paddingBottom = ''; this._updateFont(); - let height; - const persistedSize = this.findPersistedSize(); - - // If there is no persisted size, then normally render - if (!persistedSize) { - this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; - this.onContentsChanged(); - - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); - height = this._hoverWidget.containerDomNode.clientHeight + 6; - } - // When there is a persisted size then do not use a maximum height or width - else { - this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; - height = persistedSize.height; - } - this._renderingAbove = this.findRenderingPreference(height, position); + this._renderingAbove = this.findRenderingPreference(this._getHeight(), visibleData.showAtPosition); if (!this._renderingAbove) { return; } @@ -717,7 +688,7 @@ export class ResizableHoverWidget extends ResizableContentWidget { // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor - if (!persistedSize) { + if (!this.findPersistedSize()) { this.onContentsChanged(); } @@ -745,6 +716,28 @@ export class ResizableHoverWidget extends ResizableContentWidget { } } + private _getHeight(): number { + let height; + const persistedSize = this.findPersistedSize(); + // If there is no persisted size, then normally render + if (!persistedSize) { + this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this._editor.render(); + height = this._hoverWidget.containerDomNode.clientHeight + 6; + } + // When there is a persisted size then do not use a maximum height or width + else { + this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; + height = persistedSize.height; + } + return height; + } + private _layoutContentWidget(): void { this._editor.layoutContentWidget(this); this._hoverWidget.onContentsChanged(); @@ -823,10 +816,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { this._layoutContentWidget(); } - public clear(): void { - this._hoverWidget.contentsDomNode.textContent = ''; - } - public focus(): void { this._hoverWidget.containerDomNode.focus(); } @@ -876,10 +865,6 @@ export class ResizableHoverWidget extends ResizableContentWidget { public escape(): void { this._editor.focus(); } - - public clearPersistedSizes(): void { - this._persistingMechanism.clear(); - } } export class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 4ba34ad4f1843..50358f1154c75 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -4,36 +4,35 @@ *--------------------------------------------------------------------------------------------*/ import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import * as dom from 'vs/base/browser/dom'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { clamp } from 'vs/base/common/numbers'; import { ResourceMap } from 'vs/base/common/map'; -import { IPosition } from 'vs/editor/common/core/position'; +import { IPosition, Position } from 'vs/editor/common/core/position'; -export abstract class ResizableContentWidget extends Disposable implements IContentWidget { +abstract class ResizableContentWidget extends Disposable implements IContentWidget { allowEditorOverflow?: boolean | undefined; suppressMouseDown?: boolean | undefined; protected readonly _contentNode: HTMLDivElement; protected readonly _resizableNode = this._register(new ResizableHTMLElement()); - protected readonly _persistingMechanism: SingleSizePersistingMechanism | MultipleSizePersistingMechanism; private _contentPosition: IContentWidgetPosition | null = null; private _resizing: boolean = false; constructor( - initialSize: dom.IDimension = new dom.Dimension(100, 100), - private readonly _persistingOptions: IPersistingOptions, - protected readonly _editor: ICodeEditor + protected readonly _editor: ICodeEditor, + initialSize: dom.IDimension = new dom.Dimension(10, 10) ) { super(); this._contentNode = document.createElement('div'); this._contentNode.style.width = `${initialSize.width}px`; this._contentNode.style.height = `${initialSize.height}px`; + this._resizableNode.domNode.style.position = 'absolute'; this._resizableNode.domNode.appendChild(this._contentNode); this._resizableNode.minSize = new dom.Dimension(10, 10); this._resizableNode.enableSashes(true, true, true, true); @@ -48,13 +47,6 @@ export abstract class ResizableContentWidget extends Disposable implements ICont this._register(this._resizableNode.onDidWillResize(() => { this._resizing = true; })); - if (this._persistingOptions instanceof SingleSizePersistingOptions) { - this._persistingMechanism = new SingleSizePersistingMechanism(this, this._editor, this._persistingOptions); - } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { - this._persistingMechanism = new MultipleSizePersistingMechanism(this, this._editor); - } else { - throw new Error('Please specify a valid persisting mechanism'); - } } abstract getId(): string; @@ -121,22 +113,12 @@ export abstract class ResizableContentWidget extends Disposable implements ICont this._contentPosition = contentPosition; } - // abstract beforeRender?(): IDimension | null; - - afterRender(position: ContentWidgetPositionPreference | null): void { - // TODO: set max sizes that were computed above - } - abstract resize(dimension: dom.Dimension): void; get resizing() { return this._resizing; } - findPersistedSize(): dom.Dimension | undefined { - return this._persistingMechanism.findSize(); - } - beforeOnDidWillResize() { return; } @@ -150,61 +132,77 @@ export abstract class ResizableContentWidget extends Disposable implements ICont } } -interface IPersistingOptions { } +/** + * Class which is used in the single size persisting mechanism for resizable widgets. + */ +class PersistedWidgetSize { -export class SingleSizePersistingOptions implements IPersistingOptions { constructor( - public readonly key: string, - public readonly defaultSize: dom.Dimension, - @IStorageService public readonly storageService: IStorageService + private readonly _key: string, + private readonly _service: IStorageService ) { } -} - -export class MultipleSizePersistingOptions implements IPersistingOptions { - constructor() { } -} - -interface IPersistingMechanism extends IDisposable { - /** - * Method which returns the current appropriate persisted size of the widget. - */ - findSize(): dom.Dimension | undefined; + 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; + } - /** - * Method which clears the persisted size(s) of the widget. - */ - clear(): void; + store(size: dom.Dimension) { + this._service.store(this._key, JSON.stringify(size), StorageScope.PROFILE, StorageTarget.MACHINE); + } - /** - * Method which disposes the persisting mechanism. - */ - dispose(): void; + reset(): void { + this._service.remove(this._key, StorageScope.PROFILE); + } } /** - * Class which can be used to define a mechanism that persists the size of a resizable widget. The persisted size is stored using the storage service. + * Class which is used in the single size persisting mechanism for resizable widgets. */ -export class SingleSizePersistingMechanism implements IPersistingMechanism { +class ResizeState { + constructor( + readonly persistedSize: dom.Dimension | undefined, + readonly currentSize: dom.Dimension, + public persistHeight = false, + public persistWidth = false, + ) { } +} + +export class SingleSizePersistingOptions { + constructor( + public readonly key: string, + public readonly defaultSize: dom.Dimension, + @IStorageService public readonly storageService: IStorageService + ) { } +} + +export abstract class SinglePersistedSizeResizableContentWidget extends ResizableContentWidget { private readonly persistedWidgetSize: PersistedWidgetSize | null = null; private readonly disposables = new DisposableStore(); constructor( - private readonly resizableWidget: ResizableContentWidget, private readonly editor: ICodeEditor, - private readonly persistingOptions: SingleSizePersistingOptions + private readonly persistingOptions: SingleSizePersistingOptions, + initialSize: dom.IDimension ) { - + super(editor, initialSize); this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); - let state: ResizeState | undefined; - this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { - this.resizableWidget.beforeOnDidWillResize(); - state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableWidget.resizableNode.size); + this.disposables.add(this.resizableNode.onDidWillResize(() => { + this.beforeOnDidWillResize(); + state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableNode.size); })); - this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { - this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); + this.disposables.add(this.resizableNode.onDidResize(e => { + this.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; @@ -216,7 +214,7 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { 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.resizableWidget.resizableNode.size; + let { width, height } = this.resizableNode.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; } @@ -226,43 +224,41 @@ export class SingleSizePersistingMechanism implements IPersistingMechanism { this.persistedWidgetSize!.store(new dom.Dimension(width, height)); } state = undefined; - this.resizableWidget.afterOnDidResize(); + this.afterOnDidResize(); })); } - findSize(): dom.Dimension | undefined { + findPersistedSize(): dom.Dimension | undefined { return this.persistedWidgetSize?.restore(); } - clear(): void { + clearPersistedSize(): void { this.persistedWidgetSize?.reset(); } - dispose(): void { + override dispose(): void { + super.dispose(); this.disposables.dispose(); } } -/** - * Class which can be used to define a mechanism which persists the sizes of a resizable widget on a per token-basis. - * The sizes are saved in a ResourceMap which maps the document URI to the token position and its dom.Dimension persisted size. - */ -export class MultipleSizePersistingMechanism implements IPersistingMechanism { +export abstract class MultiplePersistedSizeResizableContentWidget extends ResizableContentWidget { - private readonly persistedWidgetSizes: ResourceMap> = new ResourceMap>(); - private readonly disposables = new DisposableStore(); - private _position: IPosition | null = null; + private readonly _persistedWidgetSizes: ResourceMap> = new ResourceMap>(); + private readonly _disposables = new DisposableStore(); + protected _position: Position | undefined; constructor( - private readonly resizableWidget: ResizableContentWidget, - public readonly editor: ICodeEditor + public readonly editor: ICodeEditor, + initialSize?: dom.IDimension ) { - this.disposables.add(this.editor.onDidChangeModelContent((e) => { + super(editor, initialSize); + this._disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; - if (!uri || !this.persistedWidgetSizes.has(uri)) { + if (!uri || !this._persistedWidgetSizes.has(uri)) { return; } - const persistedSizesForUri = this.persistedWidgetSizes.get(uri)!; + const persistedSizesForUri = this._persistedWidgetSizes.get(uri)!; const updatedPersistedSizesForUri = new Map(); for (const change of e.changes) { const changeOffset = change.rangeOffset; @@ -282,15 +278,15 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { } } } - this.persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); + this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); - this.disposables.add(this.resizableWidget.resizableNode.onDidWillResize(() => { - this.resizableWidget.beforeOnDidWillResize(); + this._disposables.add(this.resizableNode.onDidWillResize(() => { + this.beforeOnDidWillResize(); })); - this.disposables.add(this.resizableWidget.resizableNode.onDidResize(e => { + this._disposables.add(this.resizableNode.onDidResize(e => { const height = e.dimension.height; const width = e.dimension.width; - this.resizableWidget.resize(new dom.Dimension(width, height)); + this.resize(new dom.Dimension(width, height)); if (e.done) { if (!this.editor.hasModel()) { return; @@ -307,24 +303,28 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; - if (!this.persistedWidgetSizes.get(uri)) { + if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); - this.persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); + this._persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); } else { - const persistedWidgetSizesForUri = this.persistedWidgetSizes.get(uri)!; + const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } } - this.resizableWidget.afterOnDidResize(); + this.afterOnDidResize(); })); } - set position(position: IPosition) { + set position(position: Position | undefined) { this._position = position; } - findSize(): dom.Dimension | undefined { + get position() { + return this._position; + } + + findPersistedSize(): dom.Dimension | undefined { if (!this._position || !this.editor.hasModel()) { return; } @@ -335,62 +335,19 @@ export class MultipleSizePersistingMechanism implements IPersistingMechanism { const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; const uri = this.editor.getModel().uri; - const persistedSizesForUri = this.persistedWidgetSizes.get(uri); + const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; } return persistedSizesForUri.get(JSON.stringify([offset, length])); } - clear(): void { - this.persistedWidgetSizes.clear(); + clearPersistedSizes(): void { + this._persistedWidgetSizes.clear(); } - dispose(): void { - this.disposables.dispose(); + override dispose(): void { + super.dispose(); + this._disposables.dispose(); } } - -/** - * Class which is used in the single size persisting mechanism for resizable widgets. - */ -class PersistedWidgetSize { - - constructor( - private readonly _key: string, - private readonly _service: IStorageService - ) { } - - 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); - } -} - -/** - * Class which is used in the single size persisting mechanism for resizable widgets. - */ -class ResizeState { - constructor( - readonly persistedSize: dom.Dimension | undefined, - readonly currentSize: dom.Dimension, - public persistHeight = false, - public persistWidth = false, - ) { } -} From ab7aefd029183305b43265c99d0207580f0288e9 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 16:33:04 +0200 Subject: [PATCH 53/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 200 +++++++++--------- src/vs/editor/contrib/hover/browser/hover.ts | 4 +- .../hover/browser/resizableContentWidget.ts | 108 ++++------ 3 files changed, 146 insertions(+), 166 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index ef6d413545510..58283c195a1e4 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -452,6 +452,7 @@ const SCROLLBAR_WIDTH = 10; const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; const DELTA_SASH_LENGTH = 4; +const HORIZONTAL_SCROLLING_BY = 30; export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentWidget { @@ -465,10 +466,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW // TODO: above private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); - private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this.contextKeyService); - private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this.contextKeyService); private readonly _focusTracker: dom.IFocusTracker; - private readonly _horizontalScrollingBy: number = 30; + private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); + private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); public get isColorPickerVisible(): boolean { return Boolean(this._visibleData?.colorPicker); @@ -483,12 +483,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } constructor( - editor: ICodeEditor, - @IContextKeyService private readonly contextKeyService: IContextKeyService + _editor: ICodeEditor, + @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { - super(editor); - this.resizableNode.domNode.style.zIndex = '50'; - dom.append(this.resizableNode.domNode, this._hoverWidget.containerDomNode); + super(_editor); + this._resizableNode.domNode.style.zIndex = '50'; + dom.append(this._resizableNode.domNode, this._hoverWidget.containerDomNode); this._focusTracker = this._disposableStore.add(dom.trackFocus(this._hoverWidget.contentsDomNode)); this._disposableStore.add(this._editor.onDidLayoutChange(() => this._layout())); @@ -498,21 +498,28 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } })); this._disposableStore.add(this._focusTracker.onDidFocus(() => { + console.log('inside of on did focus'); this._hoverFocusedKey.set(true); })); this._disposableStore.add(this._focusTracker.onDidBlur(() => { + console.log('inside of on did blur'); this._hoverFocusedKey.set(false); })); this._setVisibleData(undefined); this._layout(); } + public override dispose(): void { + super.dispose(); + this._visibleData?.disposables.dispose(); + this._editor.removeContentWidget(this); + } + public getId(): string { return ResizableHoverWidget.ID; } - public resize(size: dom.Dimension) { - + public _resize(size: dom.Dimension) { this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; @@ -534,29 +541,29 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._hoverWidget.contentsDomNode.style.height = height + 'px'; } const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - this.resizableNode.northSash.el.style.width = horizontalSashLength; - this.resizableNode.southSash.el.style.width = horizontalSashLength; - this.resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - this.resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this._resizableNode.northSash.el.style.width = horizontalSashLength; + this._resizableNode.southSash.el.style.width = horizontalSashLength; + this._resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + this._resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - this.resizableNode.eastSash.el.style.height = verticalSashLength; - this.resizableNode.westSash.el.style.height = verticalSashLength; - this.resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - this.resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this._resizableNode.eastSash.el.style.height = verticalSashLength; + this._resizableNode.westSash.el.style.height = verticalSashLength; + this._resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + this._resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - const maxRenderingWidth = this.findMaximumRenderingWidth(); - const maxRenderingHeight = this.findMaximumRenderingHeight(); + const maxRenderingWidth = this._findMaximumRenderingWidth(); + const maxRenderingHeight = this._findMaximumRenderingHeight(); console.log('maxRenderingWidth : ', maxRenderingWidth); console.log('maxRenderingHeight : ', maxRenderingHeight); if (!maxRenderingWidth || !maxRenderingHeight) { return; } - this.resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); + this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); this._hoverWidget.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); } - public findAvailableSpaceVertically(): number | undefined { + private _findAvailableSpaceVertically(): number | undefined { if (!this._editor || !this._editor.hasModel() || !this._visibleData?.showAtPosition) { return; } @@ -573,12 +580,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return availableSpace; } - public findAvailableSpaceHorizontally(): number | undefined { - return this.findMaximumRenderingWidth(); + private _findAvailableSpaceHorizontally(): number | undefined { + return this._findMaximumRenderingWidth(); } - public findMaximumRenderingHeight(): number | undefined { - const availableSpace = this.findAvailableSpaceVertically(); + private _findMaximumRenderingHeight(): number | undefined { + const availableSpace = this._findAvailableSpaceVertically(); if (!availableSpace) { return; } @@ -592,7 +599,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return Math.min(availableSpace, divMaxHeight); } - public findMaximumRenderingWidth(): number | undefined { + private _findMaximumRenderingWidth(): number | undefined { if (!this._editor || !this._editor.hasModel()) { return; } @@ -604,12 +611,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } - public override dispose(): void { - super.dispose(); - this._visibleData?.disposables.dispose(); - this._editor.removeContentWidget(this); - } - public isMouseGettingCloser(posx: number, posy: number): boolean { if (!this._visibleData) { return false; @@ -626,6 +627,8 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); // TODO: do we need the following? + console.log('distance : ', distance); + console.log('this._visibleData.closestMouseDistance : ', this._visibleData.closestMouseDistance); if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; @@ -635,10 +638,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _setVisibleData(visibleData: ContentHoverVisibleData | undefined): void { - if (this._visibleData) { - this._visibleData.disposables.dispose(); - } + this._visibleData?.disposables.dispose(); this._visibleData = visibleData; + this._position = visibleData?.showAtPosition; this._hoverVisibleKey.set(!!this._visibleData); this._hoverWidget.containerDomNode.classList.toggle('hidden', !this._visibleData); } @@ -658,11 +660,43 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW codeClasses.forEach(node => this._editor.applyFontInfo(node)); } + private _updateContent(node: DocumentFragment): void { + this._hoverWidget.contentsDomNode.style.paddingBottom = ''; + this._hoverWidget.contentsDomNode.textContent = ''; + this._hoverWidget.contentsDomNode.appendChild(node); + } + + + + private _getWidgetHeight(): number { + const persistedSize = this.findPersistedSize(); + // If there is no persisted size, then normally render + if (!persistedSize) { + this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; + this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this._editor.render(); + return this._hoverWidget.containerDomNode.clientHeight + 6; + } + // When there is a persisted size then do not use a maximum height or width + else { + this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; + return persistedSize.height; + } + } + + private _layoutContentWidget(): void { + this._editor.layoutContentWidget(this); + this._hoverWidget.onContentsChanged(); + } + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { if (!this._editor || !this._editor.hasModel()) { return; } - this._position = visibleData.showAtPosition; this._setVisibleData(visibleData); const widgetPosition: IContentWidgetPosition = { position: visibleData.showAtPosition, @@ -670,28 +704,26 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW positionAffinity: visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, preference: [ContentWidgetPositionPreference.ABOVE] }; - this.setPosition(widgetPosition); + this._contentPosition = widgetPosition; + console.log('this._visible : ', this._visible); + console.log('this._visibleKey.get() : ', this._hoverVisibleKey.get()); if (!this._visible) { this._editor.addContentWidget(this); } - this._hoverWidget.contentsDomNode.style.paddingBottom = ''; - this._hoverWidget.contentsDomNode.textContent = ''; - this._hoverWidget.contentsDomNode.appendChild(node); this._updateFont(); - - this._renderingAbove = this.findRenderingPreference(this._getHeight(), visibleData.showAtPosition); + this._updateContent(node); + this._renderingAbove = this.findRenderingPreference(this._getWidgetHeight(), visibleData.showAtPosition); if (!this._renderingAbove) { return; } widgetPosition.preference = [this._renderingAbove]; - this.setPosition(widgetPosition); + this._contentPosition = widgetPosition; // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!this.findPersistedSize()) { this.onContentsChanged(); } - if (visibleData.stoleFocus) { this._hoverWidget.containerDomNode.focus(); } @@ -700,10 +732,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } public hide(): void { - this._visible = false; - this.resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); - this.resizableNode.clearSashHoverState(); + this._resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); + this._resizableNode.clearSashHoverState(); this._editor.removeContentWidget(this); if (this._visibleData) { const stoleFocus = this._visibleData.stoleFocus; @@ -716,43 +747,14 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _getHeight(): number { - let height; - const persistedSize = this.findPersistedSize(); - // If there is no persisted size, then normally render - if (!persistedSize) { - this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; - this.onContentsChanged(); - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); - height = this._hoverWidget.containerDomNode.clientHeight + 6; - } - // When there is a persisted size then do not use a maximum height or width - else { - this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; - height = persistedSize.height; - } - return height; - } - - private _layoutContentWidget(): void { - this._editor.layoutContentWidget(this); - this._hoverWidget.onContentsChanged(); - } - public onContentsChanged(): void { - - const persistedSize = this.findPersistedSize(); const containerDomNode = this._hoverWidget.containerDomNode; const contentsDomNode = this._hoverWidget.contentsDomNode; - + const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined if (persistedSize) { - const width = Math.min(this.findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); - const height = Math.min(this.findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); + const width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); + const height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); containerDomNode.style.width = width + 'px'; containerDomNode.style.height = height + 'px'; contentsDomNode.style.width = width + 'px'; @@ -764,23 +766,19 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; // Added because otherwise the initial size of the hover content is smaller than should be - this.resizableNode.domNode.style.width = this._editor.getLayoutInfo().width + 'px'; - this.resizableNode.domNode.style.height = this._editor.getLayoutInfo().height + 'px'; + this._resizableNode.domNode.style.width = this._editor.getLayoutInfo().width + 'px'; + this._resizableNode.domNode.style.height = this._editor.getLayoutInfo().height + 'px'; this._layoutContentWidget(); // Added otherwise rendered too small horizontally containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; } - const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; - - this.resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this.resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this.resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - + this._resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); + this._resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this._resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { @@ -788,7 +786,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW if (this._hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; } - const maxRenderingHeight = this.findMaximumRenderingHeight(); + const maxRenderingHeight = this._findMaximumRenderingHeight(); if (!maxRenderingHeight) { return; } @@ -801,18 +799,16 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; } } - const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; - - this.resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; - this.resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; - this.resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; - this.resizableNode.westSash.el.style.height = verticalSashLength + 'px'; - this.resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this.resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; + this._resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; + this._resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; + this._resizableNode.westSash.el.style.height = verticalSashLength + 'px'; + this._resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; this._layoutContentWidget(); } @@ -834,12 +830,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW public scrollLeft(): void { const scrollLeft = this._hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - HORIZONTAL_SCROLLING_BY }); } public scrollRight(): void { const scrollLeft = this._hoverWidget.scrollbar.getScrollPosition().scrollLeft; - this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); + this._hoverWidget.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + HORIZONTAL_SCROLLING_BY }); } public pageUp(): void { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 7c07608280d19..26ace1bc8fd33 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -165,7 +165,7 @@ export class ModesHoverController implements IEditorContribution { } if (target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID) { - // mouse down on top of overlay margin hover widget + // mouse moved on top of overlay margin hover widget return; } @@ -691,7 +691,7 @@ class ClearPersistedHoverSizes extends EditorAction { }); } - public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { + public run(accessor: ServicesAccessor, editor: ICodeEditor): void { const controller = ModesHoverController.get(editor); if (!controller) { return; diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 50358f1154c75..11d315cb264ad 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -6,37 +6,37 @@ import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; -import * as dom from 'vs/base/browser/dom'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { clamp } from 'vs/base/common/numbers'; import { ResourceMap } from 'vs/base/common/map'; import { IPosition, Position } from 'vs/editor/common/core/position'; +import * as dom from 'vs/base/browser/dom'; abstract class ResizableContentWidget extends Disposable implements IContentWidget { - allowEditorOverflow?: boolean | undefined; - suppressMouseDown?: boolean | undefined; + readonly allowEditorOverflow: boolean = true; + readonly suppressMouseDown: boolean = false; protected readonly _contentNode: HTMLDivElement; protected readonly _resizableNode = this._register(new ResizableHTMLElement()); + protected _contentPosition: IContentWidgetPosition | null = null; - private _contentPosition: IContentWidgetPosition | null = null; private _resizing: boolean = false; constructor( protected readonly _editor: ICodeEditor, - initialSize: dom.IDimension = new dom.Dimension(10, 10) + _initialSize: dom.IDimension = new dom.Dimension(10, 10) ) { super(); this._contentNode = document.createElement('div'); - this._contentNode.style.width = `${initialSize.width}px`; - this._contentNode.style.height = `${initialSize.height}px`; + this._contentNode.style.width = `${_initialSize.width}px`; + this._contentNode.style.height = `${_initialSize.height}px`; this._resizableNode.domNode.style.position = 'absolute'; this._resizableNode.domNode.appendChild(this._contentNode); this._resizableNode.minSize = new dom.Dimension(10, 10); this._resizableNode.enableSashes(true, true, true, true); - this._resizableNode.layout(initialSize.height, initialSize.width); + this._resizableNode.layout(_initialSize.height, _initialSize.width); this._register(this._resizableNode.onDidResize(e => { this._contentNode.style.width = `${e.dimension.width}px`; this._contentNode.style.height = `${e.dimension.height}px`; @@ -65,36 +65,26 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg return; } let height = widgetHeight; - // The dimensions of the document in which we are displaying the hover const bodyBox = dom.getClientArea(document.body); // Hard-coded in the hover.css file as 1.5em or 24px const minHeight = 24; - // The full height is already passed in as a parameter - const fullHeight = widgetHeight; const editorBox = dom.getDomNodePagePosition(editorDomNode); const mouseBox = this._editor.getScrolledVisiblePosition(showAtPosition); if (!mouseBox) { return; } - // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position const availableSpaceBelow = bodyBox.height - mouseBottom; - // Max height below is the minimum of the available space below and the full height of the widget - const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); - // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor + const maxHeightBelow = Math.min(availableSpaceBelow, widgetHeight); const availableSpaceAbove = editorBox.top + mouseBox.top - 30; - const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); - // We find the maximum height of the widget possible on the top or on the bottom - const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); - + const maxHeightAbove = Math.min(availableSpaceAbove, widgetHeight); + const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), widgetHeight); if (widgetHeight < minHeight) { height = minHeight; } if (height > maxHeight) { height = maxHeight; } - // Determining whether we should render above or not ideally let renderingAbove: ContentWidgetPositionPreference; if (this._editor.getOption(EditorOption.hover).above) { renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; @@ -102,18 +92,14 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } if (renderingAbove === ContentWidgetPositionPreference.ABOVE) { - this.resizableNode.enableSashes(true, true, false, false); + this._resizableNode.enableSashes(true, true, false, false); } else { - this.resizableNode.enableSashes(false, true, true, false); + this._resizableNode.enableSashes(false, true, true, false); } return renderingAbove; } - setPosition(contentPosition: IContentWidgetPosition | null): void { - this._contentPosition = contentPosition; - } - - abstract resize(dimension: dom.Dimension): void; + abstract _resize(dimension: dom.Dimension): void; get resizing() { return this._resizing; @@ -126,10 +112,6 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg afterOnDidResize() { return; } - - get resizableNode(): ResizableHTMLElement { - return this._resizableNode; - } } /** @@ -187,22 +169,24 @@ export class SingleSizePersistingOptions { export abstract class SinglePersistedSizeResizableContentWidget extends ResizableContentWidget { private readonly persistedWidgetSize: PersistedWidgetSize | null = null; + private readonly _persistingOptions: SingleSizePersistingOptions; private readonly disposables = new DisposableStore(); constructor( - private readonly editor: ICodeEditor, - private readonly persistingOptions: SingleSizePersistingOptions, - initialSize: dom.IDimension + _editor: ICodeEditor, + _persistingOptions: SingleSizePersistingOptions, + _initialSize?: dom.IDimension ) { - super(editor, initialSize); - this.persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService); + super(_editor, _initialSize); + this._persistingOptions = _persistingOptions; + this.persistedWidgetSize = new PersistedWidgetSize(this._persistingOptions.key, this._persistingOptions.storageService); let state: ResizeState | undefined; - this.disposables.add(this.resizableNode.onDidWillResize(() => { + this.disposables.add(this._resizableNode.onDidWillResize(() => { this.beforeOnDidWillResize(); - state = new ResizeState(this.persistedWidgetSize!.restore(), this.resizableNode.size); + state = new ResizeState(this.persistedWidgetSize!.restore(), this._resizableNode.size); })); - this.disposables.add(this.resizableNode.onDidResize(e => { - this.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); + this.disposables.add(this._resizableNode.onDidResize(e => { + this._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; @@ -211,15 +195,15 @@ export abstract class SinglePersistedSizeResizableContentWidget extends Resizabl return; } if (state) { - const fontInfo = this.editor.getOption(EditorOption.fontInfo); - const itemHeight = clamp(this.editor.getOption(EditorOption.suggestLineHeight) || fontInfo.lineHeight, 8, 1000); + 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.resizableNode.size; + let { width, height } = this._resizableNode.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { - height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; + 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; + width = state.persistedSize?.width ?? this._persistingOptions.defaultSize.width; } this.persistedWidgetSize!.store(new dom.Dimension(width, height)); } @@ -249,12 +233,12 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza protected _position: Position | undefined; constructor( - public readonly editor: ICodeEditor, - initialSize?: dom.IDimension + _editor: ICodeEditor, + _initialSize?: dom.IDimension ) { - super(editor, initialSize); - this._disposables.add(this.editor.onDidChangeModelContent((e) => { - const uri = this.editor.getModel()?.uri; + super(_editor, _initialSize); + this._disposables.add(this._editor.onDidChangeModelContent((e) => { + const uri = this._editor.getModel()?.uri; if (!uri || !this._persistedWidgetSizes.has(uri)) { return; } @@ -280,27 +264,27 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza } this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); - this._disposables.add(this.resizableNode.onDidWillResize(() => { + this._disposables.add(this._resizableNode.onDidWillResize(() => { this.beforeOnDidWillResize(); })); - this._disposables.add(this.resizableNode.onDidResize(e => { + this._disposables.add(this._resizableNode.onDidResize(e => { const height = e.dimension.height; const width = e.dimension.width; - this.resize(new dom.Dimension(width, height)); + this._resize(new dom.Dimension(width, height)); if (e.done) { - if (!this.editor.hasModel()) { + if (!this._editor.hasModel()) { return; } - const uri = this.editor.getModel().uri; + const uri = this._editor.getModel().uri; if (!uri || !this._position) { return; } const persistedSize = new dom.Dimension(width, height); - const wordPosition = this.editor.getModel().getWordAtPosition(this._position); + const wordPosition = this._editor.getModel().getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); + const offset = this._editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; if (!this._persistedWidgetSizes.get(uri)) { @@ -325,16 +309,16 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza } findPersistedSize(): dom.Dimension | undefined { - if (!this._position || !this.editor.hasModel()) { + if (!this._position || !this._editor.hasModel()) { return; } - const wordPosition = this.editor.getModel().getWordAtPosition(this._position); + const wordPosition = this._editor.getModel().getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); + const offset = this._editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; - const uri = this.editor.getModel().uri; + const uri = this._editor.getModel().uri; const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; From bffeeb0e5691cd0c79e75854f793d8e466e17cbe Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 16:52:19 +0200 Subject: [PATCH 54/72] cleaning the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 58283c195a1e4..7ba2c99e14e2b 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -490,7 +490,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._resizableNode.domNode.style.zIndex = '50'; dom.append(this._resizableNode.domNode, this._hoverWidget.containerDomNode); - this._focusTracker = this._disposableStore.add(dom.trackFocus(this._hoverWidget.contentsDomNode)); + this._focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); this._disposableStore.add(this._editor.onDidLayoutChange(() => this._layout())); this._disposableStore.add(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { @@ -498,11 +498,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } })); this._disposableStore.add(this._focusTracker.onDidFocus(() => { - console.log('inside of on did focus'); this._hoverFocusedKey.set(true); })); this._disposableStore.add(this._focusTracker.onDidBlur(() => { - console.log('inside of on did blur'); this._hoverFocusedKey.set(false); })); this._setVisibleData(undefined); @@ -553,8 +551,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const maxRenderingWidth = this._findMaximumRenderingWidth(); const maxRenderingHeight = this._findMaximumRenderingHeight(); - console.log('maxRenderingWidth : ', maxRenderingWidth); - console.log('maxRenderingHeight : ', maxRenderingHeight); if (!maxRenderingWidth || !maxRenderingHeight) { return; } @@ -626,10 +622,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - // TODO: do we need the following? - console.log('distance : ', distance); - console.log('this._visibleData.closestMouseDistance : ', this._visibleData.closestMouseDistance); - if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + if (distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } @@ -705,8 +698,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW preference: [ContentWidgetPositionPreference.ABOVE] }; this._contentPosition = widgetPosition; - console.log('this._visible : ', this._visible); - console.log('this._visibleKey.get() : ', this._hoverVisibleKey.get()); if (!this._visible) { this._editor.addContentWidget(this); } From 9aca64d6af8881c6db38a587b15e4fd0c247bbc1 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 16:56:24 +0200 Subject: [PATCH 55/72] removing the unecessary _visible variable, the context key already serves the purpose --- src/vs/editor/contrib/hover/browser/contentHover.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 7ba2c99e14e2b..8ac5dea786cef 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -461,9 +461,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _disposableStore = new DisposableStore(); private _visibleData: ContentHoverVisibleData | undefined; private _renderingAbove: ContentWidgetPositionPreference | undefined; - // TODO: change so as to use directly the _hoverVisibleKey instead of the boolean here - private _visible: boolean = false; - // TODO: above private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); private readonly _focusTracker: dom.IFocusTracker; @@ -690,7 +687,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW if (!this._editor || !this._editor.hasModel()) { return; } - this._setVisibleData(visibleData); const widgetPosition: IContentWidgetPosition = { position: visibleData.showAtPosition, secondaryPosition: visibleData.showAtSecondaryPosition, @@ -698,9 +694,10 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW preference: [ContentWidgetPositionPreference.ABOVE] }; this._contentPosition = widgetPosition; - if (!this._visible) { + if (!this._hoverVisibleKey.get()) { this._editor.addContentWidget(this); } + this._setVisibleData(visibleData); this._updateFont(); this._updateContent(node); this._renderingAbove = this.findRenderingPreference(this._getWidgetHeight(), visibleData.showAtPosition); @@ -719,11 +716,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._hoverWidget.containerDomNode.focus(); } visibleData.colorPicker?.layout(); - this._visible = true; } public hide(): void { - this._visible = false; this._resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); this._resizableNode.clearSashHoverState(); this._editor.removeContentWidget(this); From b1795375610fcbc26a534e4a134ddaafa61eb81c Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Tue, 30 May 2023 17:24:40 +0200 Subject: [PATCH 56/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 32 +++++++++--------- .../hover/browser/resizableContentWidget.ts | 33 ++++++++++--------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 8ac5dea786cef..ebb78628b6152 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -463,7 +463,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _renderingAbove: ContentWidgetPositionPreference | undefined; private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); - private readonly _focusTracker: dom.IFocusTracker; private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); @@ -487,17 +486,17 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._resizableNode.domNode.style.zIndex = '50'; dom.append(this._resizableNode.domNode, this._hoverWidget.containerDomNode); - this._focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); + const focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); this._disposableStore.add(this._editor.onDidLayoutChange(() => this._layout())); this._disposableStore.add(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); - this._disposableStore.add(this._focusTracker.onDidFocus(() => { + this._disposableStore.add(focusTracker.onDidFocus(() => { this._hoverFocusedKey.set(true); })); - this._disposableStore.add(this._focusTracker.onDidBlur(() => { + this._disposableStore.add(focusTracker.onDidBlur(() => { this._hoverFocusedKey.set(false); })); this._setVisibleData(undefined); @@ -507,6 +506,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW public override dispose(): void { super.dispose(); this._visibleData?.disposables.dispose(); + this._disposableStore.dispose(); this._editor.removeContentWidget(this); } @@ -660,7 +660,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _getWidgetHeight(): number { const persistedSize = this.findPersistedSize(); - // If there is no persisted size, then normally render + // If there is no persisted size, then render normally if (!persistedSize) { this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; @@ -733,6 +733,16 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } + private _setSize(width: string, height: string) { + const containerDomNode = this._hoverWidget.containerDomNode; + const contentsDomNode = this._hoverWidget.contentsDomNode; + containerDomNode.style.width = width; + containerDomNode.style.height = height; + contentsDomNode.style.width = width; + contentsDomNode.style.height = height; + this._layoutContentWidget(); + } + public onContentsChanged(): void { const containerDomNode = this._hoverWidget.containerDomNode; const contentsDomNode = this._hoverWidget.contentsDomNode; @@ -741,20 +751,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW if (persistedSize) { const width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); const height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); - containerDomNode.style.width = width + 'px'; - containerDomNode.style.height = height + 'px'; - contentsDomNode.style.width = width + 'px'; - contentsDomNode.style.height = height + 'px'; - this._layoutContentWidget(); + this._setSize(width + 'px', height + 'px'); } else { - containerDomNode.style.width = 'auto'; - containerDomNode.style.height = 'auto'; - contentsDomNode.style.width = 'auto'; - contentsDomNode.style.height = 'auto'; // Added because otherwise the initial size of the hover content is smaller than should be this._resizableNode.domNode.style.width = this._editor.getLayoutInfo().width + 'px'; this._resizableNode.domNode.style.height = this._editor.getLayoutInfo().height + 'px'; - this._layoutContentWidget(); + this._setSize('auto', 'auto'); // Added otherwise rendered too small horizontally containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 11d315cb264ad..be3d8301bcf43 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -166,11 +166,14 @@ export class SingleSizePersistingOptions { ) { } } +/** + * Abstract class which defines a resizable widgets for which one single global size is persisted. + */ export abstract class SinglePersistedSizeResizableContentWidget extends ResizableContentWidget { - private readonly persistedWidgetSize: PersistedWidgetSize | null = null; + private readonly _persistedWidgetSize: PersistedWidgetSize | undefined; private readonly _persistingOptions: SingleSizePersistingOptions; - private readonly disposables = new DisposableStore(); + private readonly _disposables = new DisposableStore(); constructor( _editor: ICodeEditor, @@ -179,22 +182,20 @@ export abstract class SinglePersistedSizeResizableContentWidget extends Resizabl ) { super(_editor, _initialSize); this._persistingOptions = _persistingOptions; - this.persistedWidgetSize = new PersistedWidgetSize(this._persistingOptions.key, this._persistingOptions.storageService); + this._persistedWidgetSize = new PersistedWidgetSize(this._persistingOptions.key, this._persistingOptions.storageService); let state: ResizeState | undefined; - this.disposables.add(this._resizableNode.onDidWillResize(() => { + this._disposables.add(this._resizableNode.onDidWillResize(() => { this.beforeOnDidWillResize(); - state = new ResizeState(this.persistedWidgetSize!.restore(), this._resizableNode.size); + state = new ResizeState(this._persistedWidgetSize!.restore(), this._resizableNode.size); })); - this.disposables.add(this._resizableNode.onDidResize(e => { + this._disposables.add(this._resizableNode.onDidResize(e => { this._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) { + state.persistHeight = state.persistHeight || !!e.north || !!e.south; + state.persistWidth = state.persistWidth || !!e.east || !!e.west; 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); @@ -205,7 +206,7 @@ export abstract class SinglePersistedSizeResizableContentWidget extends Resizabl 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)); + this._persistedWidgetSize!.store(new dom.Dimension(width, height)); } state = undefined; this.afterOnDidResize(); @@ -213,19 +214,22 @@ export abstract class SinglePersistedSizeResizableContentWidget extends Resizabl } findPersistedSize(): dom.Dimension | undefined { - return this.persistedWidgetSize?.restore(); + return this._persistedWidgetSize?.restore(); } clearPersistedSize(): void { - this.persistedWidgetSize?.reset(); + this._persistedWidgetSize?.reset(); } override dispose(): void { super.dispose(); - this.disposables.dispose(); + this._disposables.dispose(); } } +/** + * Abstract class which defines a resizable widgets for which a size is persisted on a per token basis. The persisted sizes are updated as the the model changes. + */ export abstract class MultiplePersistedSizeResizableContentWidget extends ResizableContentWidget { private readonly _persistedWidgetSizes: ResourceMap> = new ResourceMap>(); @@ -286,7 +290,6 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza } const offset = this._editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; - if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); From c49aa40ebf381862982f8b5e4d9525b006c172f8 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 12 Jun 2023 11:48:11 +0200 Subject: [PATCH 57/72] cleaning the code --- src/vs/base/browser/ui/hover/hover.css | 4 + .../contrib/hover/browser/contentHover.ts | 169 ++++++++++-------- .../hover/browser/resizableContentWidget.ts | 7 +- 3 files changed, 109 insertions(+), 71 deletions(-) diff --git a/src/vs/base/browser/ui/hover/hover.css b/src/vs/base/browser/ui/hover/hover.css index 5f867a8913f07..b9b27186be9f1 100644 --- a/src/vs/base/browser/ui/hover/hover.css +++ b/src/vs/base/browser/ui/hover/hover.css @@ -3,6 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.resizable-hover { + z-index: 50; +} + .monaco-hover { cursor: default; position: absolute; diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index ebb78628b6152..0724599464b0a 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -67,7 +67,6 @@ export class ContentHoverController extends Disposable { })); this._register(TokenizationRegistry.onDidChange(() => { if (this._widget.position && this._currentResult) { - this._widget.clearPersistedSizes(); this._setCurrentResult(this._currentResult); // render again } })); @@ -453,6 +452,7 @@ const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; const DELTA_SASH_LENGTH = 4; const HORIZONTAL_SCROLLING_BY = 30; +const HEADER_HEIGHT = 30; export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentWidget { @@ -483,7 +483,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { super(_editor); - this._resizableNode.domNode.style.zIndex = '50'; + this._resizableNode.domNode.classList.add('resizable-hover'); dom.append(this._resizableNode.domNode, this._hoverWidget.containerDomNode); const focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); @@ -514,44 +514,70 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return ResizableHoverWidget.ID; } - public _resize(size: dom.Dimension) { - this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; - const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this._hoverWidget.containerDomNode.style.width = width; - this._hoverWidget.contentsDomNode.style.width = width; - const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this._hoverWidget.containerDomNode.style.height = height + 'px'; + private _setHoverWidgetSize(width: number | string, height: number | string) { + const transformedWidth = typeof width === 'number' ? `${width}px` : width; + const transformedHeight = typeof height === 'number' ? `${height}px` : height; + const containerDomNode = this._hoverWidget.containerDomNode; + const contentsDomNode = this._hoverWidget.contentsDomNode; + containerDomNode.style.width = transformedWidth; + containerDomNode.style.height = transformedHeight; + contentsDomNode.style.width = transformedWidth; + contentsDomNode.style.height = transformedHeight; + this._layoutContentWidget(); + } + private _adjustForHorizontalScrollbar(height: number) { + const contentsDomNode = this._hoverWidget.contentsDomNode; const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = scrollDimensions.scrollWidth > scrollDimensions.width; if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this._hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { + contentsDomNode.style.paddingBottom = extraBottomPadding; } - this._hoverWidget.contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; + contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; } else { - this._hoverWidget.contentsDomNode.style.height = height + 'px'; + contentsDomNode.style.height = height + 'px'; } + } + + private _setAdjustedHoverWidgetSize(size: dom.Dimension): void { + this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; + this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; + const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; + this._setHoverWidgetSize(width, height); + this._adjustForHorizontalScrollbar(height); + } + + private _setSashSizes(size: dom.Dimension): void { + const northSashElement = this._resizableNode.northSash.el; + const soushSashElement = this._resizableNode.southSash.el; const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - this._resizableNode.northSash.el.style.width = horizontalSashLength; - this._resizableNode.southSash.el.style.width = horizontalSashLength; - this._resizableNode.northSash.el.style.left = 2 * BORDER_WIDTH + 'px'; - this._resizableNode.southSash.el.style.left = 2 * BORDER_WIDTH + 'px'; + northSashElement.style.width = horizontalSashLength; + soushSashElement.style.width = horizontalSashLength; + northSashElement.style.left = 2 * BORDER_WIDTH + 'px'; + soushSashElement.style.left = 2 * BORDER_WIDTH + 'px'; + const eashSashElement = this._resizableNode.eastSash.el; + const westSashElement = this._resizableNode.westSash.el; const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - this._resizableNode.eastSash.el.style.height = verticalSashLength; - this._resizableNode.westSash.el.style.height = verticalSashLength; - this._resizableNode.eastSash.el.style.top = 2 * BORDER_WIDTH + 'px'; - this._resizableNode.westSash.el.style.top = 2 * BORDER_WIDTH + 'px'; + eashSashElement.style.height = verticalSashLength; + westSashElement.style.height = verticalSashLength; + eashSashElement.style.top = 2 * BORDER_WIDTH + 'px'; + westSashElement.style.top = 2 * BORDER_WIDTH + 'px'; + } + private _setMaxSize() { const maxRenderingWidth = this._findMaximumRenderingWidth(); const maxRenderingHeight = this._findMaximumRenderingHeight(); - if (!maxRenderingWidth || !maxRenderingHeight) { - return; - } - this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); + this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth ?? Infinity, maxRenderingHeight ?? Infinity); + } + + public _resize(size: dom.Dimension) { + this._setAdjustedHoverWidgetSize(size); + this._setSashSizes(size); + this._setMaxSize(); this._hoverWidget.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); } @@ -565,9 +591,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const bodyBox = dom.getClientArea(document.body); let availableSpace: number; if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableSpace = editorBox.top + mouseBox.top - 30; + availableSpace = editorBox.top + mouseBox.top - HEADER_HEIGHT; } else { - const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; + const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; availableSpace = bodyBox.height - mouseBottom; } return availableSpace; @@ -639,10 +665,11 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); - this._hoverWidget.contentsDomNode.style.fontSize = `${fontSize}px`; - this._hoverWidget.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - this._hoverWidget.contentsDomNode.style.maxHeight = `${height}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + const contentsDomNode = this._hoverWidget.contentsDomNode; + contentsDomNode.style.fontSize = `${fontSize}px`; + contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; + contentsDomNode.style.maxHeight = `${height}px`; + contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { @@ -651,29 +678,32 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _updateContent(node: DocumentFragment): void { - this._hoverWidget.contentsDomNode.style.paddingBottom = ''; - this._hoverWidget.contentsDomNode.textContent = ''; - this._hoverWidget.contentsDomNode.appendChild(node); + const contentsDomNode = this._hoverWidget.contentsDomNode; + contentsDomNode.style.paddingBottom = ''; + contentsDomNode.textContent = ''; + contentsDomNode.appendChild(node); } private _getWidgetHeight(): number { + const containerDomNode = this._hoverWidget.containerDomNode; + const contentsDomNode = this._hoverWidget.contentsDomNode; const persistedSize = this.findPersistedSize(); // If there is no persisted size, then render normally if (!persistedSize) { - this._hoverWidget.contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; - this._hoverWidget.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; + contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this._editor.render(); - return this._hoverWidget.containerDomNode.clientHeight + 6; + return containerDomNode.clientHeight + 2 * SASH_WIDTH_MINUS_BORDER; } // When there is a persisted size then do not use a maximum height or width else { - this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; + contentsDomNode.style.maxHeight = 'none'; + contentsDomNode.style.maxWidth = 'none'; return persistedSize.height; } } @@ -683,29 +713,33 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._hoverWidget.onContentsChanged(); } - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { - if (!this._editor || !this._editor.hasModel()) { - return; + private _render(node: DocumentFragment, visibleData: ContentHoverVisibleData) { + if (!this._hoverVisibleKey.get()) { + this._editor.addContentWidget(this); } + this._setVisibleData(visibleData); + this._updateFont(); + this._updateContent(node); + } + + private _setContentPosition(visibleData: ContentHoverVisibleData, preference?: ContentWidgetPositionPreference) { const widgetPosition: IContentWidgetPosition = { position: visibleData.showAtPosition, secondaryPosition: visibleData.showAtSecondaryPosition, positionAffinity: visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, - preference: [ContentWidgetPositionPreference.ABOVE] + preference: [preference ?? ContentWidgetPositionPreference.ABOVE] }; this._contentPosition = widgetPosition; - if (!this._hoverVisibleKey.get()) { - this._editor.addContentWidget(this); - } - this._setVisibleData(visibleData); - this._updateFont(); - this._updateContent(node); - this._renderingAbove = this.findRenderingPreference(this._getWidgetHeight(), visibleData.showAtPosition); - if (!this._renderingAbove) { + } + + public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + if (!this._editor || !this._editor.hasModel()) { return; } - widgetPosition.preference = [this._renderingAbove]; - this._contentPosition = widgetPosition; + this._setContentPosition(visibleData); + this._render(node, visibleData); + this._renderingAbove = this._findRenderingPreference(this._getWidgetHeight(), visibleData.showAtPosition) ?? ContentWidgetPositionPreference.ABOVE; + this._setContentPosition(visibleData, this._renderingAbove); // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor @@ -733,14 +767,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _setSize(width: string, height: string) { - const containerDomNode = this._hoverWidget.containerDomNode; - const contentsDomNode = this._hoverWidget.contentsDomNode; - containerDomNode.style.width = width; - containerDomNode.style.height = height; - contentsDomNode.style.width = width; - contentsDomNode.style.height = height; - this._layoutContentWidget(); + private _setResizableDomNodeSize(width: number, height: number): void { + this._resizableNode.domNode.style.width = `${width}px`; + this._resizableNode.domNode.style.height = `${height}px`; } public onContentsChanged(): void { @@ -751,28 +780,28 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW if (persistedSize) { const width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); const height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); - this._setSize(width + 'px', height + 'px'); + this._setHoverWidgetSize(width, height); } else { // Added because otherwise the initial size of the hover content is smaller than should be - this._resizableNode.domNode.style.width = this._editor.getLayoutInfo().width + 'px'; - this._resizableNode.domNode.style.height = this._editor.getLayoutInfo().height + 'px'; - this._setSize('auto', 'auto'); + const layoutInfo = this._editor.getLayoutInfo(); + this._setResizableDomNodeSize(layoutInfo.width, layoutInfo.height); + this._setHoverWidgetSize('auto', 'auto'); // Added otherwise rendered too small horizontally containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; } const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; this._resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this._resizableNode.domNode.style.width = clientWidth + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; - this._resizableNode.domNode.style.height = clientHeight + 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + this._setResizableDomNodeSize(clientWidth + 2 * SASH_WIDTH_MINUS_BORDER, clientHeight + 2 * SASH_WIDTH_MINUS_BORDER); + containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (this._hoverWidget.contentsDomNode.style.paddingBottom !== extraBottomPadding) { - this._hoverWidget.contentsDomNode.style.paddingBottom = extraBottomPadding; + if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { + contentsDomNode.style.paddingBottom = extraBottomPadding; } const maxRenderingHeight = this._findMaximumRenderingHeight(); if (!maxRenderingHeight) { diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index be3d8301bcf43..b4659e3bf5756 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -59,7 +59,7 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg return this._contentPosition; } - findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { + protected _findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { const editorDomNode = this._editor.getDomNode(); if (!editorDomNode) { return; @@ -166,6 +166,11 @@ export class SingleSizePersistingOptions { ) { } } +/** + * TODO: Add another class for the resizable content widget, where using the idea that Alex had mentioned + */ + + /** * Abstract class which defines a resizable widgets for which one single global size is persisted. */ From 01131a68cc9d726563e132171bd28b2ca40f7416 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 12 Jun 2023 16:01:44 +0200 Subject: [PATCH 58/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 192 ++++++++++-------- 1 file changed, 105 insertions(+), 87 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 0724599464b0a..505c6832d2880 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -514,70 +514,91 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return ResizableHoverWidget.ID; } - private _setHoverWidgetSize(width: number | string, height: number | string) { + private _setDimensions(container: HTMLElement, width: number | string, height: number | string) { const transformedWidth = typeof width === 'number' ? `${width}px` : width; const transformedHeight = typeof height === 'number' ? `${height}px` : height; - const containerDomNode = this._hoverWidget.containerDomNode; + container.style.width = transformedWidth; + container.style.height = transformedHeight; + } + + private _setContentsDomNodeDimensions(width: number | string, height: number | string) { const contentsDomNode = this._hoverWidget.contentsDomNode; - containerDomNode.style.width = transformedWidth; - containerDomNode.style.height = transformedHeight; - contentsDomNode.style.width = transformedWidth; - contentsDomNode.style.height = transformedHeight; + return this._setDimensions(contentsDomNode, width, height); + } + + private _setContainerDomNodeDimensions(width: number | string, height: number | string) { + const containerDomNode = this._hoverWidget.containerDomNode; + return this._setDimensions(containerDomNode, width, height); + } + + private _setHoverWidgetDimensions(width: number | string, height: number | string) { + this._setContentsDomNodeDimensions(width, height); + this._setContainerDomNodeDimensions(width, height); this._layoutContentWidget(); } - private _adjustForHorizontalScrollbar(height: number) { - const contentsDomNode = this._hoverWidget.contentsDomNode; + private _hasHorizontalScrollbar(): boolean { const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = scrollDimensions.scrollWidth > scrollDimensions.width; - if (hasHorizontalScrollbar) { - // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible - const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { - contentsDomNode.style.paddingBottom = extraBottomPadding; - } - contentsDomNode.style.height = height - SCROLLBAR_WIDTH + 'px'; - } else { - contentsDomNode.style.height = height + 'px'; + return hasHorizontalScrollbar; + } + + private _adjustBottomPadding() { + const contentsDomNode = this._hoverWidget.contentsDomNode; + const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; + if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { + contentsDomNode.style.paddingBottom = extraBottomPadding; } } - private _setAdjustedHoverWidgetSize(size: dom.Dimension): void { - this._hoverWidget.contentsDomNode.style.maxHeight = 'none'; - this._hoverWidget.contentsDomNode.style.maxWidth = 'none'; - const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER + 'px'; + private _setContentsDomNodeMaxDimensions(width: number | string, height: number | string) { + const transformedWidth = typeof width === 'number' ? `${width}px` : width; + const transformedHeight = typeof height === 'number' ? `${height}px` : height; + const contentsDomNode = this._hoverWidget.contentsDomNode; + contentsDomNode.style.maxWidth = transformedWidth; + contentsDomNode.style.maxHeight = transformedHeight; + } + + private _setAdjustedHoverWidgetDimensions(size: dom.Dimension): void { + this._setContentsDomNodeMaxDimensions('none', 'none'); + const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER; const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; - this._setHoverWidgetSize(width, height); - this._adjustForHorizontalScrollbar(height); + this._setHoverWidgetDimensions(width, height); + if (this._hasHorizontalScrollbar()) { + this._adjustBottomPadding(); + this._setContentsDomNodeDimensions(width, height - SCROLLBAR_WIDTH); + } } - private _setSashSizes(size: dom.Dimension): void { + private _setSashDimensions(horizontalSashLength: number, horizontalSashLeft: number, verticalSashLength: number, verticalSashTop: number) {// size: dom.Dimension): void { const northSashElement = this._resizableNode.northSash.el; const soushSashElement = this._resizableNode.southSash.el; - const horizontalSashLength = size.width - DELTA_SASH_LENGTH + 'px'; - northSashElement.style.width = horizontalSashLength; - soushSashElement.style.width = horizontalSashLength; - northSashElement.style.left = 2 * BORDER_WIDTH + 'px'; - soushSashElement.style.left = 2 * BORDER_WIDTH + 'px'; + const horizontalSashLengthInPx = horizontalSashLength + 'px'; + northSashElement.style.width = horizontalSashLengthInPx; + soushSashElement.style.width = horizontalSashLengthInPx; + const horizontalSashLeftInPx = horizontalSashLeft + 'px'; + northSashElement.style.left = horizontalSashLeftInPx; + soushSashElement.style.left = horizontalSashLeftInPx; const eashSashElement = this._resizableNode.eastSash.el; const westSashElement = this._resizableNode.westSash.el; - const verticalSashLength = size.height - DELTA_SASH_LENGTH + 'px'; - eashSashElement.style.height = verticalSashLength; - westSashElement.style.height = verticalSashLength; - eashSashElement.style.top = 2 * BORDER_WIDTH + 'px'; - westSashElement.style.top = 2 * BORDER_WIDTH + 'px'; + const verticalSashLengthInPx = verticalSashLength + 'px'; + eashSashElement.style.height = verticalSashLengthInPx; + westSashElement.style.height = verticalSashLengthInPx; + const verticalSashTopInPx = verticalSashTop + 'px'; + eashSashElement.style.top = verticalSashTopInPx; + westSashElement.style.top = verticalSashTopInPx; } - private _setMaxSize() { + private _setResizableNodeMaxDimensions() { const maxRenderingWidth = this._findMaximumRenderingWidth(); const maxRenderingHeight = this._findMaximumRenderingHeight(); this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth ?? Infinity, maxRenderingHeight ?? Infinity); } public _resize(size: dom.Dimension) { - this._setAdjustedHoverWidgetSize(size); - this._setSashSizes(size); - this._setMaxSize(); + this._setAdjustedHoverWidgetDimensions(size); + this._setSashDimensions(size.width - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH, size.height - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH); + this._setResizableNodeMaxDimensions(); this._hoverWidget.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); } @@ -668,8 +689,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const contentsDomNode = this._hoverWidget.contentsDomNode; contentsDomNode.style.fontSize = `${fontSize}px`; contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; - contentsDomNode.style.maxHeight = `${height}px`; - contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + this._setContentsDomNodeMaxDimensions(Math.max(this._editor.getLayoutInfo().width * 0.66, 500), height); } private _updateFont(): void { @@ -688,13 +708,14 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _getWidgetHeight(): number { const containerDomNode = this._hoverWidget.containerDomNode; - const contentsDomNode = this._hoverWidget.contentsDomNode; const persistedSize = this.findPersistedSize(); // If there is no persisted size, then render normally if (!persistedSize) { - contentsDomNode.style.maxHeight = `${Math.max(this._editor.getLayoutInfo().height / 4, 250)}px`; - contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + this._setContentsDomNodeMaxDimensions( + Math.max(this._editor.getLayoutInfo().width * 0.66, 500), + Math.max(this._editor.getLayoutInfo().height / 4, 250)); this.onContentsChanged(); + // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this._editor.render(); @@ -702,8 +723,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } // When there is a persisted size then do not use a maximum height or width else { - contentsDomNode.style.maxHeight = 'none'; - contentsDomNode.style.maxWidth = 'none'; + this._setContentsDomNodeMaxDimensions('none', 'none'); return persistedSize.height; } } @@ -738,7 +758,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } this._setContentPosition(visibleData); this._render(node, visibleData); - this._renderingAbove = this._findRenderingPreference(this._getWidgetHeight(), visibleData.showAtPosition) ?? ContentWidgetPositionPreference.ABOVE; + const widgetHeight = this._getWidgetHeight(); + const widgetPosition = visibleData.showAtPosition; + this._renderingAbove = this._findRenderingPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE; this._setContentPosition(visibleData, this._renderingAbove); // See https://github.com/microsoft/vscode/issues/140339 @@ -767,65 +789,61 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _setResizableDomNodeSize(width: number, height: number): void { + private _setResizableDomNodeDimensions(width: number, height: number): void { + this._resizableNode.layout(height, width); this._resizableNode.domNode.style.width = `${width}px`; this._resizableNode.domNode.style.height = `${height}px`; } - public onContentsChanged(): void { + private _setPersistedHoverDimensionsOrRenderNormally(): void { const containerDomNode = this._hoverWidget.containerDomNode; - const contentsDomNode = this._hoverWidget.contentsDomNode; const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined if (persistedSize) { const width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); const height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); - this._setHoverWidgetSize(width, height); + this._setHoverWidgetDimensions(width, height); } else { // Added because otherwise the initial size of the hover content is smaller than should be const layoutInfo = this._editor.getLayoutInfo(); - this._setResizableDomNodeSize(layoutInfo.width, layoutInfo.height); - this._setHoverWidgetSize('auto', 'auto'); + this._setResizableDomNodeDimensions(layoutInfo.width, layoutInfo.height); + this._setHoverWidgetDimensions('auto', 'auto'); // Added otherwise rendered too small horizontally - containerDomNode.style.width = containerDomNode.clientWidth + 2 * BORDER_WIDTH + 'px'; + this._setContainerDomNodeDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, containerDomNode.clientHeight); + } + } + + private _setContainerAbsolutePosition(top: number, left: number): void { + const containerDomNode = this._hoverWidget.containerDomNode; + containerDomNode.style.top = top + 'px'; + containerDomNode.style.left = left + 'px'; + } + + private _adjustHoverHeightForScrollbar(height: number) { + const containerDomNode = this._hoverWidget.containerDomNode; + const contentsDomNode = this._hoverWidget.contentsDomNode; + const maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity; + let hoverHeight: number = height; + const persistedSize = this.findPersistedSize(); + if (persistedSize) { + hoverHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; } + this._setContainerDomNodeDimensions(containerDomNode.clientWidth, Math.min(maxRenderingHeight, hoverHeight)); + this._setContentsDomNodeDimensions(contentsDomNode.clientWidth, Math.min(maxRenderingHeight, hoverHeight - SCROLLBAR_WIDTH)); + } + + public onContentsChanged(): void { + this._setPersistedHoverDimensionsOrRenderNormally(); + const containerDomNode = this._hoverWidget.containerDomNode; const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; - this._resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); - this._setResizableDomNodeSize(clientWidth + 2 * SASH_WIDTH_MINUS_BORDER, clientHeight + 2 * SASH_WIDTH_MINUS_BORDER); - - containerDomNode.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - containerDomNode.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); - const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); - if (hasHorizontalScrollbar) { - const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; - if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { - contentsDomNode.style.paddingBottom = extraBottomPadding; - } - const maxRenderingHeight = this._findMaximumRenderingHeight(); - if (!maxRenderingHeight) { - return; - } - if (persistedSize) { - const persistedHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; - containerDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedHeight - SCROLLBAR_WIDTH) + 'px'; - } else { - containerDomNode.style.height = Math.min(maxRenderingHeight, clientHeight) + 'px'; - contentsDomNode.style.height = Math.min(maxRenderingHeight, clientHeight - SCROLLBAR_WIDTH) + 'px'; - } + this._setResizableDomNodeDimensions(clientWidth + 2 * SASH_WIDTH_MINUS_BORDER, clientHeight + 2 * SASH_WIDTH_MINUS_BORDER); + this._setContainerAbsolutePosition(SASH_WIDTH_MINUS_BORDER - 1, SASH_WIDTH_MINUS_BORDER - 1); + if (this._hasHorizontalScrollbar()) { + this._adjustBottomPadding(); + this._adjustHoverHeightForScrollbar(clientHeight); } - const verticalSashLength = containerDomNode.clientHeight + 2 * BORDER_WIDTH; - const horizontalSashLength = containerDomNode.clientWidth + 2 * BORDER_WIDTH; - this._resizableNode.northSash.el.style.width = horizontalSashLength + 'px'; - this._resizableNode.southSash.el.style.width = horizontalSashLength + 'px'; - this._resizableNode.northSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this._resizableNode.southSash.el.style.left = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this._resizableNode.eastSash.el.style.height = verticalSashLength + 'px'; - this._resizableNode.westSash.el.style.height = verticalSashLength + 'px'; - this._resizableNode.eastSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; - this._resizableNode.westSash.el.style.top = SASH_WIDTH_MINUS_BORDER - 1 + 'px'; + this._setSashDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1, containerDomNode.clientHeight + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1); this._layoutContentWidget(); } From c0aa848824112e159dfea2a40b3c28c0675753de Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 12 Jun 2023 16:58:54 +0200 Subject: [PATCH 59/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 114 ++++++++++-------- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- 2 files changed, 63 insertions(+), 53 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 505c6832d2880..9b98307b303c9 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -22,7 +22,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { AsyncIterableObject } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MultiplePersistedSizeResizableContentWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; const $ = dom.$; @@ -294,7 +294,7 @@ export class ContentHoverController extends Disposable { })); } - this._widget.showAt(fragment, new ContentHoverVisibleData( + this._widget.showAt(fragment, new ContentHoverData( colorPicker, showAtPosition, showAtSecondaryPosition, @@ -428,7 +428,7 @@ class FilteredHoverResult extends HoverResult { } } -class ContentHoverVisibleData { +class ContentHoverData { public closestMouseDistance: number | undefined = undefined; @@ -459,12 +459,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW public static ID = 'editor.contrib.resizableContentHoverWidget'; private _disposableStore = new DisposableStore(); - private _visibleData: ContentHoverVisibleData | undefined; + private _visibleData: ContentHoverData | undefined; private _renderingAbove: ContentWidgetPositionPreference | undefined; private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); - private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); - private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); + private readonly _hoverVisibleKey: IContextKey; + private readonly _hoverFocusedKey: IContextKey; public get isColorPickerVisible(): boolean { return Boolean(this._visibleData?.colorPicker); @@ -480,19 +480,22 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW constructor( _editor: ICodeEditor, - @IContextKeyService private readonly _contextKeyService: IContextKeyService + @IContextKeyService _contextKeyService: IContextKeyService ) { super(_editor); - this._resizableNode.domNode.classList.add('resizable-hover'); + this._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(_contextKeyService); + this._hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(_contextKeyService); + dom.append(this._resizableNode.domNode, this._hoverWidget.containerDomNode); + this._resizableNode.domNode.classList.add('resizable-hover'); - const focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); this._disposableStore.add(this._editor.onDidLayoutChange(() => this._layout())); this._disposableStore.add(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); + const focusTracker = this._disposableStore.add(dom.trackFocus(this._resizableNode.domNode)); this._disposableStore.add(focusTracker.onDidFocus(() => { this._hoverFocusedKey.set(true); })); @@ -537,13 +540,21 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._layoutContentWidget(); } + private _setContentsDomNodeMaxDimensions(width: number | string, height: number | string) { + const transformedWidth = typeof width === 'number' ? `${width}px` : width; + const transformedHeight = typeof height === 'number' ? `${height}px` : height; + const contentsDomNode = this._hoverWidget.contentsDomNode; + contentsDomNode.style.maxWidth = transformedWidth; + contentsDomNode.style.maxHeight = transformedHeight; + } + private _hasHorizontalScrollbar(): boolean { const scrollDimensions = this._hoverWidget.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = scrollDimensions.scrollWidth > scrollDimensions.width; return hasHorizontalScrollbar; } - private _adjustBottomPadding() { + private _adjustContentsBottomPadding() { const contentsDomNode = this._hoverWidget.contentsDomNode; const extraBottomPadding = `${this._hoverWidget.scrollbar.options.horizontalScrollbarSize}px`; if (contentsDomNode.style.paddingBottom !== extraBottomPadding) { @@ -551,21 +562,13 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _setContentsDomNodeMaxDimensions(width: number | string, height: number | string) { - const transformedWidth = typeof width === 'number' ? `${width}px` : width; - const transformedHeight = typeof height === 'number' ? `${height}px` : height; - const contentsDomNode = this._hoverWidget.contentsDomNode; - contentsDomNode.style.maxWidth = transformedWidth; - contentsDomNode.style.maxHeight = transformedHeight; - } - private _setAdjustedHoverWidgetDimensions(size: dom.Dimension): void { this._setContentsDomNodeMaxDimensions('none', 'none'); const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER; const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; this._setHoverWidgetDimensions(width, height); if (this._hasHorizontalScrollbar()) { - this._adjustBottomPadding(); + this._adjustContentsBottomPadding(); this._setContentsDomNodeDimensions(width, height - SCROLLBAR_WIDTH); } } @@ -597,8 +600,8 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW public _resize(size: dom.Dimension) { this._setAdjustedHoverWidgetDimensions(size); - this._setSashDimensions(size.width - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH, size.height - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH); this._setResizableNodeMaxDimensions(); + this._setSashDimensions(size.width - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH, size.height - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH); this._hoverWidget.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); } @@ -610,14 +613,14 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const editorBox = dom.getDomNodePagePosition(this._editor.getDomNode()); const mouseBox = this._editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); - let availableSpace: number; + let availableVerticalSpace: number; if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableSpace = editorBox.top + mouseBox.top - HEADER_HEIGHT; + availableVerticalSpace = editorBox.top + mouseBox.top - HEADER_HEIGHT; } else { const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - availableSpace = bodyBox.height - mouseBottom; + availableVerticalSpace = bodyBox.height - mouseBottom; } - return availableSpace; + return availableVerticalSpace; } private _findAvailableSpaceHorizontally(): number | undefined { @@ -629,14 +632,14 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW if (!availableSpace) { return; } - let divMaxHeight = 3 * SASH_WIDTH_MINUS_BORDER; - for (const childHtmlElement of this._hoverWidget.contentsDomNode.children) { - divMaxHeight += childHtmlElement.clientHeight; + let maximumHeight = 3 * SASH_WIDTH_MINUS_BORDER; + for (const hoverPart of this._hoverWidget.contentsDomNode.children) { + maximumHeight += hoverPart.clientHeight; } - if (this._hoverWidget.contentsDomNode.clientWidth < this._hoverWidget.contentsDomNode.scrollWidth) { - divMaxHeight += SCROLLBAR_WIDTH; + if (this._hasHorizontalScrollbar()) { + maximumHeight += SCROLLBAR_WIDTH; } - return Math.min(availableSpace, divMaxHeight); + return Math.min(availableSpace, maximumHeight); } private _findMaximumRenderingWidth(): number | undefined { @@ -674,10 +677,10 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return true; } - private _setVisibleData(visibleData: ContentHoverVisibleData | undefined): void { + private _setVisibleData(visibleData: ContentHoverData | undefined): void { + this._position = visibleData?.showAtPosition; this._visibleData?.disposables.dispose(); this._visibleData = visibleData; - this._position = visibleData?.showAtPosition; this._hoverVisibleKey.set(!!this._visibleData); this._hoverWidget.containerDomNode.classList.toggle('hidden', !this._visibleData); } @@ -704,26 +707,13 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW contentsDomNode.appendChild(node); } - - private _getWidgetHeight(): number { const containerDomNode = this._hoverWidget.containerDomNode; const persistedSize = this.findPersistedSize(); - // If there is no persisted size, then render normally if (!persistedSize) { - this._setContentsDomNodeMaxDimensions( - Math.max(this._editor.getLayoutInfo().width * 0.66, 500), - Math.max(this._editor.getLayoutInfo().height / 4, 250)); - this.onContentsChanged(); - - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); return containerDomNode.clientHeight + 2 * SASH_WIDTH_MINUS_BORDER; } - // When there is a persisted size then do not use a maximum height or width else { - this._setContentsDomNodeMaxDimensions('none', 'none'); return persistedSize.height; } } @@ -733,16 +723,35 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._hoverWidget.onContentsChanged(); } - private _render(node: DocumentFragment, visibleData: ContentHoverVisibleData) { + private _updateContentsDomNodeMaxDimensions() { + const persistedSize = this.findPersistedSize(); + if (!persistedSize) { + this._setContentsDomNodeMaxDimensions( + Math.max(this._editor.getLayoutInfo().width * 0.66, 500), + Math.max(this._editor.getLayoutInfo().height / 4, 250)); + } + else { + this._setContentsDomNodeMaxDimensions('none', 'none'); + } + } + + private _render(node: DocumentFragment, visibleData: ContentHoverData) { if (!this._hoverVisibleKey.get()) { this._editor.addContentWidget(this); } this._setVisibleData(visibleData); this._updateFont(); this._updateContent(node); + this._updateContentsDomNodeMaxDimensions(); + if (!this.findPersistedSize()) { + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this._editor.render(); + } } - private _setContentPosition(visibleData: ContentHoverVisibleData, preference?: ContentWidgetPositionPreference) { + private _setContentPosition(visibleData: ContentHoverData, preference?: ContentWidgetPositionPreference) { const widgetPosition: IContentWidgetPosition = { position: visibleData.showAtPosition, secondaryPosition: visibleData.showAtSecondaryPosition, @@ -752,7 +761,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._contentPosition = widgetPosition; } - public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { + public showAt(node: DocumentFragment, visibleData: ContentHoverData): void { if (!this._editor || !this._editor.hasModel()) { return; } @@ -791,12 +800,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _setResizableDomNodeDimensions(width: number, height: number): void { this._resizableNode.layout(height, width); - this._resizableNode.domNode.style.width = `${width}px`; - this._resizableNode.domNode.style.height = `${height}px`; + const resizableDomNode = this._resizableNode.domNode; + resizableDomNode.style.width = `${width}px`; + resizableDomNode.style.height = `${height}px`; } private _setPersistedHoverDimensionsOrRenderNormally(): void { - const containerDomNode = this._hoverWidget.containerDomNode; const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined if (persistedSize) { @@ -809,6 +818,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._setResizableDomNodeDimensions(layoutInfo.width, layoutInfo.height); this._setHoverWidgetDimensions('auto', 'auto'); // Added otherwise rendered too small horizontally + const containerDomNode = this._hoverWidget.containerDomNode; this._setContainerDomNodeDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, containerDomNode.clientHeight); } } @@ -840,7 +850,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._setResizableDomNodeDimensions(clientWidth + 2 * SASH_WIDTH_MINUS_BORDER, clientHeight + 2 * SASH_WIDTH_MINUS_BORDER); this._setContainerAbsolutePosition(SASH_WIDTH_MINUS_BORDER - 1, SASH_WIDTH_MINUS_BORDER - 1); if (this._hasHorizontalScrollbar()) { - this._adjustBottomPadding(); + this._adjustContentsBottomPadding(); this._adjustHoverHeightForScrollbar(clientHeight); } this._setSashDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1, containerDomNode.clientHeight + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1); diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 26ace1bc8fd33..f78e27bb019c9 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -691,7 +691,7 @@ class ClearPersistedHoverSizes extends EditorAction { }); } - public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { const controller = ModesHoverController.get(editor); if (!controller) { return; From 7f1a666a16f838da03b2053f0d3a20b447535849 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Mon, 12 Jun 2023 17:31:21 +0200 Subject: [PATCH 60/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 21 ++---- .../hover/browser/resizableContentWidget.ts | 73 +++++++++++-------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 9b98307b303c9..b72724e367b39 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -446,13 +446,11 @@ class ContentHoverData { ) { } } - +const HORIZONTAL_SCROLLING_BY = 30; const SCROLLBAR_WIDTH = 10; +const DELTA_SASH_LENGTH = 4; const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; -const DELTA_SASH_LENGTH = 4; -const HORIZONTAL_SCROLLING_BY = 30; -const HEADER_HEIGHT = 30; export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentWidget { @@ -598,7 +596,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth ?? Infinity, maxRenderingHeight ?? Infinity); } - public _resize(size: dom.Dimension) { + override _resize(size: dom.Dimension) { this._setAdjustedHoverWidgetDimensions(size); this._setResizableNodeMaxDimensions(); this._setSashDimensions(size.width - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH, size.height - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH); @@ -607,18 +605,15 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _findAvailableSpaceVertically(): number | undefined { - if (!this._editor || !this._editor.hasModel() || !this._visibleData?.showAtPosition) { + if (!this._visibleData?.showAtPosition) { return; } - const editorBox = dom.getDomNodePagePosition(this._editor.getDomNode()); - const mouseBox = this._editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); - const bodyBox = dom.getClientArea(document.body); - let availableVerticalSpace: number; + const position = this._visibleData.showAtPosition; + let availableVerticalSpace: number | undefined; if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableVerticalSpace = editorBox.top + mouseBox.top - HEADER_HEIGHT; + availableVerticalSpace = this._availableVerticalSpaceAbove(position); } else { - const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - availableVerticalSpace = bodyBox.height - mouseBottom; + availableVerticalSpace = this._availableVerticalSpaceBelow(position); } return availableVerticalSpace; } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index b4659e3bf5756..5487115403b06 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -13,6 +13,9 @@ import { ResourceMap } from 'vs/base/common/map'; import { IPosition, Position } from 'vs/editor/common/core/position'; import * as dom from 'vs/base/browser/dom'; +const HEADER_HEIGHT = 30; +const MIN_HEIGHT = 24; + abstract class ResizableContentWidget extends Disposable implements IContentWidget { readonly allowEditorOverflow: boolean = true; @@ -49,6 +52,10 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg })); } + get resizing() { + return this._resizing; + } + abstract getId(): string; getDomNode(): HTMLElement { @@ -59,32 +66,39 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg return this._contentPosition; } - protected _findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { + protected _availableVerticalSpaceAbove(position: IPosition): number | undefined { const editorDomNode = this._editor.getDomNode(); if (!editorDomNode) { return; } - let height = widgetHeight; - const bodyBox = dom.getClientArea(document.body); - // Hard-coded in the hover.css file as 1.5em or 24px - const minHeight = 24; + const mouseBox = this._editor.getScrolledVisiblePosition(position); + if (!mouseBox) { + return; + } const editorBox = dom.getDomNodePagePosition(editorDomNode); - const mouseBox = this._editor.getScrolledVisiblePosition(showAtPosition); + return editorBox.top + mouseBox.top - HEADER_HEIGHT; + } + + protected _availableVerticalSpaceBelow(position: IPosition): number | undefined { + const editorDomNode = this._editor.getDomNode(); + if (!editorDomNode) { + return; + } + const mouseBox = this._editor.getScrolledVisiblePosition(position); if (!mouseBox) { return; } + const editorBox = dom.getDomNodePagePosition(editorDomNode); + const bodyBox = dom.getClientArea(document.body); const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; - const availableSpaceBelow = bodyBox.height - mouseBottom; - const maxHeightBelow = Math.min(availableSpaceBelow, widgetHeight); - const availableSpaceAbove = editorBox.top + mouseBox.top - 30; - const maxHeightAbove = Math.min(availableSpaceAbove, widgetHeight); + return bodyBox.height - mouseBottom; + } + + protected _findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { + const maxHeightBelow = Math.min(this._availableVerticalSpaceBelow(showAtPosition) ?? Infinity, widgetHeight); + const maxHeightAbove = Math.min(this._availableVerticalSpaceAbove(showAtPosition) ?? Infinity, widgetHeight); const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), widgetHeight); - if (widgetHeight < minHeight) { - height = minHeight; - } - if (height > maxHeight) { - height = maxHeight; - } + const height = clamp(widgetHeight, MIN_HEIGHT, maxHeight); let renderingAbove: ContentWidgetPositionPreference; if (this._editor.getOption(EditorOption.hover).above) { renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; @@ -99,10 +113,8 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg return renderingAbove; } - abstract _resize(dimension: dom.Dimension): void; - - get resizing() { - return this._resizing; + _resize(dimension: dom.Dimension): void { + this._resizableNode.layout(dimension.height, dimension.width); } beforeOnDidWillResize() { @@ -166,11 +178,6 @@ export class SingleSizePersistingOptions { ) { } } -/** - * TODO: Add another class for the resizable content widget, where using the idea that Alex had mentioned - */ - - /** * Abstract class which defines a resizable widgets for which one single global size is persisted. */ @@ -284,16 +291,17 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza if (!this._editor.hasModel()) { return; } - const uri = this._editor.getModel().uri; + const editorModel = this._editor.getModel(); + const uri = editorModel.uri; if (!uri || !this._position) { return; } - const persistedSize = new dom.Dimension(width, height); - const wordPosition = this._editor.getModel().getWordAtPosition(this._position); + const wordPosition = editorModel.getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this._editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); + const persistedSize = new dom.Dimension(width, height); + const offset = editorModel.getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map([]); @@ -320,13 +328,14 @@ export abstract class MultiplePersistedSizeResizableContentWidget extends Resiza if (!this._position || !this._editor.hasModel()) { return; } - const wordPosition = this._editor.getModel().getWordAtPosition(this._position); + const editorModel = this._editor.getModel(); + const wordPosition = editorModel.getWordAtPosition(this._position); if (!wordPosition) { return; } - const offset = this._editor.getModel().getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); + const offset = editorModel.getOffsetAt({ lineNumber: this._position.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; - const uri = this._editor.getModel().uri; + const uri = editorModel.uri; const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; From 991bde49447ad6409755fa6e91b4ec33e2ef007e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 12:06:36 +0200 Subject: [PATCH 61/72] no longer access the sash sizes directly --- src/vs/base/browser/ui/sash/sash.ts | 79 +++++++++---------- .../contrib/hover/browser/contentHover.ts | 22 ------ 2 files changed, 39 insertions(+), 62 deletions(-) diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 4ef97c14f2ad2..b20c218516917 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -247,7 +247,7 @@ const PointerEventsDisabledCssClass = 'pointer-events-disabled'; */ export class Sash extends Disposable { - private _el: HTMLElement; + private el: HTMLElement; private layoutProvider: ISashLayoutProvider; private orientation: Orientation; private size: number; @@ -270,7 +270,6 @@ export class Sash extends Disposable { private _orthogonalEndDragHandle: HTMLElement | undefined; get state(): SashState { return this._state; } - get el(): HTMLElement { return this._el; } get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; } get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; } @@ -283,9 +282,9 @@ export class Sash extends Disposable { return; } - this._el.classList.toggle('disabled', state === SashState.Disabled); - this._el.classList.toggle('minimum', state === SashState.AtMinimum); - this._el.classList.toggle('maximum', state === SashState.AtMaximum); + this.el.classList.toggle('disabled', state === SashState.Disabled); + this.el.classList.toggle('minimum', state === SashState.AtMinimum); + this.el.classList.toggle('maximum', state === SashState.AtMaximum); this._state = state; this.onDidEnablementChange.fire(state); @@ -337,7 +336,7 @@ export class Sash extends Disposable { this.orthogonalStartDragHandleDisposables.clear(); if (state !== SashState.Disabled) { - this._orthogonalStartDragHandle = append(this._el, $('.orthogonal-drag-handle.start')); + this._orthogonalStartDragHandle = append(this.el, $('.orthogonal-drag-handle.start')); this.orthogonalStartDragHandleDisposables.add(toDisposable(() => this._orthogonalStartDragHandle!.remove())); this.orthogonalStartDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalStartDragHandleDisposables); @@ -371,7 +370,7 @@ export class Sash extends Disposable { this.orthogonalEndDragHandleDisposables.clear(); if (state !== SashState.Disabled) { - this._orthogonalEndDragHandle = append(this._el, $('.orthogonal-drag-handle.end')); + this._orthogonalEndDragHandle = append(this.el, $('.orthogonal-drag-handle.end')); this.orthogonalEndDragHandleDisposables.add(toDisposable(() => this._orthogonalEndDragHandle!.remove())); this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalEndDragHandleDisposables); @@ -407,30 +406,30 @@ export class Sash extends Disposable { constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) { super(); - this._el = append(container, $('.monaco-sash')); + this.el = append(container, $('.monaco-sash')); if (options.orthogonalEdge) { - this._el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`); + this.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`); } if (isMacintosh) { - this._el.classList.add('mac'); + this.el.classList.add('mac'); } - const onMouseDown = this._register(new DomEmitter(this._el, 'mousedown')).event; + const onMouseDown = this._register(new DomEmitter(this.el, 'mousedown')).event; this._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory()), this)); - const onMouseDoubleClick = this._register(new DomEmitter(this._el, 'dblclick')).event; + const onMouseDoubleClick = this._register(new DomEmitter(this.el, 'dblclick')).event; this._register(onMouseDoubleClick(this.onPointerDoublePress, this)); - const onMouseEnter = this._register(new DomEmitter(this._el, 'mouseenter')).event; + const onMouseEnter = this._register(new DomEmitter(this.el, 'mouseenter')).event; this._register(onMouseEnter(() => Sash.onMouseEnter(this))); - const onMouseLeave = this._register(new DomEmitter(this._el, 'mouseleave')).event; + const onMouseLeave = this._register(new DomEmitter(this.el, 'mouseleave')).event; this._register(onMouseLeave(() => Sash.onMouseLeave(this))); - this._register(Gesture.addTarget(this._el)); + this._register(Gesture.addTarget(this.el)); - const onTouchStart = this._register(new DomEmitter(this._el, EventType.Start)).event; - this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this._el)), this)); - const onTap = this._register(new DomEmitter(this._el, EventType.Tap)).event; + const onTouchStart = this._register(new DomEmitter(this.el, EventType.Start)).event; + this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this.el)), this)); + const onTap = this._register(new DomEmitter(this.el, EventType.Tap)).event; let doubleTapTimeout: any = undefined; this._register(onTap(event => { @@ -449,9 +448,9 @@ export class Sash extends Disposable { this.size = options.size; if (options.orientation === Orientation.VERTICAL) { - this._el.style.width = `${this.size}px`; + this.el.style.width = `${this.size}px`; } else { - this._el.style.height = `${this.size}px`; + this.el.style.height = `${this.size}px`; } } else { this.size = globalSize; @@ -471,14 +470,14 @@ export class Sash extends Disposable { this.orientation = options.orientation || Orientation.VERTICAL; if (this.orientation === Orientation.HORIZONTAL) { - this._el.classList.add('horizontal'); - this._el.classList.remove('vertical'); + this.el.classList.add('horizontal'); + this.el.classList.remove('vertical'); } else { - this._el.classList.remove('horizontal'); - this._el.classList.add('vertical'); + this.el.classList.remove('horizontal'); + this.el.classList.add('vertical'); } - this._el.classList.toggle('debug', DEBUG); + this.el.classList.toggle('debug', DEBUG); this.layout(); } @@ -517,11 +516,11 @@ export class Sash extends Disposable { const altKey = event.altKey; const startEvent: ISashEvent = { startX, currentX: startX, startY, currentY: startY, altKey }; - this._el.classList.add('active'); + this.el.classList.add('active'); this._onDidStart.fire(startEvent); // fix https://github.com/microsoft/vscode/issues/21675 - const style = createStyleSheet(this._el); + const style = createStyleSheet(this.el); const updateStyle = () => { let cursor = ''; @@ -566,9 +565,9 @@ export class Sash extends Disposable { const onPointerUp = (e: PointerEvent) => { EventHelper.stop(e, false); - this._el.removeChild(style); + this.el.removeChild(style); - this._el.classList.remove('active'); + this.el.classList.remove('active'); this._onDidEnd.fire(); disposables.dispose(); @@ -598,11 +597,11 @@ export class Sash extends Disposable { } private static onMouseEnter(sash: Sash, fromLinkedSash: boolean = false): void { - if (sash._el.classList.contains('active')) { + if (sash.el.classList.contains('active')) { sash.hoverDelayer.cancel(); - sash._el.classList.add('hover'); + sash.el.classList.add('hover'); } else { - sash.hoverDelayer.trigger(() => sash._el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { }); + sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { }); } if (!fromLinkedSash && sash.linkedSash) { @@ -612,7 +611,7 @@ export class Sash extends Disposable { private static onMouseLeave(sash: Sash, fromLinkedSash: boolean = false): void { sash.hoverDelayer.cancel(); - sash._el.classList.remove('hover'); + sash.el.classList.remove('hover'); if (!fromLinkedSash && sash.linkedSash) { Sash.onMouseLeave(sash.linkedSash, true); @@ -635,25 +634,25 @@ export class Sash extends Disposable { layout(): void { if (this.orientation === Orientation.VERTICAL) { const verticalProvider = (this.layoutProvider); - this._el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px'; + this.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px'; if (verticalProvider.getVerticalSashTop) { - this._el.style.top = verticalProvider.getVerticalSashTop(this) + 'px'; + this.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px'; } if (verticalProvider.getVerticalSashHeight) { - this._el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px'; + this.el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px'; } } else { const horizontalProvider = (this.layoutProvider); - this._el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px'; + this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px'; if (horizontalProvider.getHorizontalSashLeft) { - this._el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px'; + this.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px'; } if (horizontalProvider.getHorizontalSashWidth) { - this._el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px'; + this.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px'; } } } @@ -674,6 +673,6 @@ export class Sash extends Disposable { override dispose(): void { super.dispose(); - this._el.remove(); + this.el.remove(); } } diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index b72724e367b39..93fc3a61c1a23 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -448,7 +448,6 @@ class ContentHoverData { const HORIZONTAL_SCROLLING_BY = 30; const SCROLLBAR_WIDTH = 10; -const DELTA_SASH_LENGTH = 4; const SASH_WIDTH_MINUS_BORDER = 3; const BORDER_WIDTH = 1; @@ -571,25 +570,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _setSashDimensions(horizontalSashLength: number, horizontalSashLeft: number, verticalSashLength: number, verticalSashTop: number) {// size: dom.Dimension): void { - const northSashElement = this._resizableNode.northSash.el; - const soushSashElement = this._resizableNode.southSash.el; - const horizontalSashLengthInPx = horizontalSashLength + 'px'; - northSashElement.style.width = horizontalSashLengthInPx; - soushSashElement.style.width = horizontalSashLengthInPx; - const horizontalSashLeftInPx = horizontalSashLeft + 'px'; - northSashElement.style.left = horizontalSashLeftInPx; - soushSashElement.style.left = horizontalSashLeftInPx; - const eashSashElement = this._resizableNode.eastSash.el; - const westSashElement = this._resizableNode.westSash.el; - const verticalSashLengthInPx = verticalSashLength + 'px'; - eashSashElement.style.height = verticalSashLengthInPx; - westSashElement.style.height = verticalSashLengthInPx; - const verticalSashTopInPx = verticalSashTop + 'px'; - eashSashElement.style.top = verticalSashTopInPx; - westSashElement.style.top = verticalSashTopInPx; - } - private _setResizableNodeMaxDimensions() { const maxRenderingWidth = this._findMaximumRenderingWidth(); const maxRenderingHeight = this._findMaximumRenderingHeight(); @@ -599,7 +579,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW override _resize(size: dom.Dimension) { this._setAdjustedHoverWidgetDimensions(size); this._setResizableNodeMaxDimensions(); - this._setSashDimensions(size.width - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH, size.height - DELTA_SASH_LENGTH, 2 * BORDER_WIDTH); this._hoverWidget.scrollbar.scanDomNode(); this._editor.layoutContentWidget(this); } @@ -848,7 +827,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._adjustContentsBottomPadding(); this._adjustHoverHeightForScrollbar(clientHeight); } - this._setSashDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1, containerDomNode.clientHeight + 2 * BORDER_WIDTH, SASH_WIDTH_MINUS_BORDER - 1); this._layoutContentWidget(); } From 994e9bf1d44d77efd8d1210bfa9f20286a9d4e1b Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 12:07:12 +0200 Subject: [PATCH 62/72] removing the sash accessors --- src/vs/base/browser/ui/resizable/resizable.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/vs/base/browser/ui/resizable/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts index 9bd5f4ff54219..95dfb06b8d007 100644 --- a/src/vs/base/browser/ui/resizable/resizable.ts +++ b/src/vs/base/browser/ui/resizable/resizable.ts @@ -187,20 +187,4 @@ export class ResizableHTMLElement { get preferredSize() { return this._preferredSize; } - - get northSash() { - return this._northSash; - } - - get eastSash() { - return this._eastSash; - } - - get westSash() { - return this._westSash; - } - - get southSash() { - return this._southSash; - } } From 75befc2f39c89ec9839087996aab8dc4b6f68ea4 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 12:18:32 +0200 Subject: [PATCH 63/72] cleaning the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 93fc3a61c1a23..2d12b14a4ffaa 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -772,13 +772,6 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } } - private _setResizableDomNodeDimensions(width: number, height: number): void { - this._resizableNode.layout(height, width); - const resizableDomNode = this._resizableNode.domNode; - resizableDomNode.style.width = `${width}px`; - resizableDomNode.style.height = `${height}px`; - } - private _setPersistedHoverDimensionsOrRenderNormally(): void { const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined @@ -789,7 +782,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } else { // Added because otherwise the initial size of the hover content is smaller than should be const layoutInfo = this._editor.getLayoutInfo(); - this._setResizableDomNodeDimensions(layoutInfo.width, layoutInfo.height); + this._resizableNode.layout(layoutInfo.height, layoutInfo.width); this._setHoverWidgetDimensions('auto', 'auto'); // Added otherwise rendered too small horizontally const containerDomNode = this._hoverWidget.containerDomNode; @@ -821,7 +814,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const containerDomNode = this._hoverWidget.containerDomNode; const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; - this._setResizableDomNodeDimensions(clientWidth + 2 * SASH_WIDTH_MINUS_BORDER, clientHeight + 2 * SASH_WIDTH_MINUS_BORDER); + this._resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); this._setContainerAbsolutePosition(SASH_WIDTH_MINUS_BORDER - 1, SASH_WIDTH_MINUS_BORDER - 1); if (this._hasHorizontalScrollbar()) { this._adjustContentsBottomPadding(); From a1874cd38f2d519bdd483e46eecd82feaf77a7fc Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:16:59 +0200 Subject: [PATCH 64/72] removing code that appears to be redundant, resetting the width --- .../editor/contrib/hover/browser/contentHover.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 2d12b14a4ffaa..6e682127bb1d9 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -449,7 +449,6 @@ class ContentHoverData { const HORIZONTAL_SCROLLING_BY = 30; const SCROLLBAR_WIDTH = 10; const SASH_WIDTH_MINUS_BORDER = 3; -const BORDER_WIDTH = 1; export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentWidget { @@ -775,19 +774,19 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _setPersistedHoverDimensionsOrRenderNormally(): void { const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined + let width: number | string; + let height: number | string; if (persistedSize) { - const width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); - const height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); - this._setHoverWidgetDimensions(width, height); + width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); + height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); } else { // Added because otherwise the initial size of the hover content is smaller than should be const layoutInfo = this._editor.getLayoutInfo(); this._resizableNode.layout(layoutInfo.height, layoutInfo.width); - this._setHoverWidgetDimensions('auto', 'auto'); - // Added otherwise rendered too small horizontally - const containerDomNode = this._hoverWidget.containerDomNode; - this._setContainerDomNodeDimensions(containerDomNode.clientWidth + 2 * BORDER_WIDTH, containerDomNode.clientHeight); + width = 'auto'; + height = 'auto'; } + this._setHoverWidgetDimensions(width, height); } private _setContainerAbsolutePosition(top: number, left: number): void { From ebd5c655b0cd81a6f562f221c8523915e32cff65 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:17:44 +0200 Subject: [PATCH 65/72] changing the order of the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 6e682127bb1d9..96c04f149c96e 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -772,10 +772,10 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _setPersistedHoverDimensionsOrRenderNormally(): void { - const persistedSize = this.findPersistedSize(); - // Suppose a persisted size is defined let width: number | string; let height: number | string; + const persistedSize = this.findPersistedSize(); + // Suppose a persisted size is defined if (persistedSize) { width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); From 48fa43b8a989bc79c7395d1a30d3f82f72d6e365 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:25:50 +0200 Subject: [PATCH 66/72] simplifying the code, appears to not be useful --- src/vs/editor/contrib/hover/browser/contentHover.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 96c04f149c96e..8e74397d25d4d 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -799,13 +799,8 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const containerDomNode = this._hoverWidget.containerDomNode; const contentsDomNode = this._hoverWidget.contentsDomNode; const maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity; - let hoverHeight: number = height; - const persistedSize = this.findPersistedSize(); - if (persistedSize) { - hoverHeight = persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER; - } - this._setContainerDomNodeDimensions(containerDomNode.clientWidth, Math.min(maxRenderingHeight, hoverHeight)); - this._setContentsDomNodeDimensions(contentsDomNode.clientWidth, Math.min(maxRenderingHeight, hoverHeight - SCROLLBAR_WIDTH)); + this._setContainerDomNodeDimensions(containerDomNode.clientWidth, Math.min(maxRenderingHeight, height)); + this._setContentsDomNodeDimensions(contentsDomNode.clientWidth, Math.min(maxRenderingHeight, height - SCROLLBAR_WIDTH)); } public onContentsChanged(): void { From d6895191d5d19b60219d4ec003abebb7aa732e4a Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:31:31 +0200 Subject: [PATCH 67/72] simplifying the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 8e74397d25d4d..f23d82c7101f5 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -563,6 +563,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER; const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; this._setHoverWidgetDimensions(width, height); + // measure if has horizontal scorllbar after setting the dimensions if (this._hasHorizontalScrollbar()) { this._adjustContentsBottomPadding(); this._setContentsDomNodeDimensions(width, height - SCROLLBAR_WIDTH); @@ -587,13 +588,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return; } const position = this._visibleData.showAtPosition; - let availableVerticalSpace: number | undefined; - if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { - availableVerticalSpace = this._availableVerticalSpaceAbove(position); - } else { - availableVerticalSpace = this._availableVerticalSpaceBelow(position); - } - return availableVerticalSpace; + return this._renderingAbove === ContentWidgetPositionPreference.ABOVE ? this._availableVerticalSpaceAbove(position) : this._availableVerticalSpaceBelow(position); } private _findAvailableSpaceHorizontally(): number | undefined { From 18eb6fda3368efa7a9f1d76dd6b77f5401cf4446 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:45:48 +0200 Subject: [PATCH 68/72] cleaning the code --- .../contrib/hover/browser/contentHover.ts | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index f23d82c7101f5..5f93a3645bf6c 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -601,9 +601,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return; } let maximumHeight = 3 * SASH_WIDTH_MINUS_BORDER; - for (const hoverPart of this._hoverWidget.contentsDomNode.children) { + Array.from(this._hoverWidget.contentsDomNode.children).forEach((hoverPart) => { maximumHeight += hoverPart.clientHeight; - } + }); if (this._hasHorizontalScrollbar()) { maximumHeight += SCROLLBAR_WIDTH; } @@ -615,11 +615,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return; } const editorBox = dom.getDomNodePagePosition(this._editor.getDomNode()); - const widthOfEditor = editorBox.width; - const leftOfEditor = editorBox.left; const glyphMarginWidth = this._editor.getLayoutInfo().glyphMarginWidth; const leftOfContainer = this._hoverWidget.containerDomNode.offsetLeft; - return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; + return editorBox.width + editorBox.left - leftOfContainer - glyphMarginWidth; } public isMouseGettingCloser(posx: number, posy: number): boolean { @@ -645,18 +643,21 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW return true; } + private _setWidgetPosition(position: Position | undefined) { + this._position = position; + } + private _setVisibleData(visibleData: ContentHoverData | undefined): void { - this._position = visibleData?.showAtPosition; + this._setWidgetPosition(visibleData?.showAtPosition); this._visibleData?.disposables.dispose(); this._visibleData = visibleData; - this._hoverVisibleKey.set(!!this._visibleData); - this._hoverWidget.containerDomNode.classList.toggle('hidden', !this._visibleData); + this._hoverVisibleKey.set(!!visibleData); + this._hoverWidget.containerDomNode.classList.toggle('hidden', !visibleData); } private _layout(): void { const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); - const contentsDomNode = this._hoverWidget.contentsDomNode; contentsDomNode.style.fontSize = `${fontSize}px`; contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; @@ -678,12 +679,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _getWidgetHeight(): number { const containerDomNode = this._hoverWidget.containerDomNode; const persistedSize = this.findPersistedSize(); - if (!persistedSize) { - return containerDomNode.clientHeight + 2 * SASH_WIDTH_MINUS_BORDER; - } - else { - return persistedSize.height; - } + return persistedSize ? persistedSize.height : containerDomNode.clientHeight + 2 * SASH_WIDTH_MINUS_BORDER; } private _layoutContentWidget(): void { From d017077725ca69c3f9d71ca92037adb64fadc7e9 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:49:28 +0200 Subject: [PATCH 69/72] cleaning the code --- .../editor/contrib/hover/browser/contentHover.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 5f93a3645bf6c..54dfa2ff2524d 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -9,7 +9,7 @@ import { coalesce } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -689,14 +689,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW private _updateContentsDomNodeMaxDimensions() { const persistedSize = this.findPersistedSize(); - if (!persistedSize) { - this._setContentsDomNodeMaxDimensions( - Math.max(this._editor.getLayoutInfo().width * 0.66, 500), - Math.max(this._editor.getLayoutInfo().height / 4, 250)); - } - else { - this._setContentsDomNodeMaxDimensions('none', 'none'); - } + const width = persistedSize ? 'none' : Math.max(this._editor.getLayoutInfo().width * 0.66, 500); + const height = persistedSize ? 'none' : Math.max(this._editor.getLayoutInfo().height / 4, 250); + this._setContentsDomNodeMaxDimensions(width, height); } private _render(node: DocumentFragment, visibleData: ContentHoverData) { @@ -716,13 +711,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _setContentPosition(visibleData: ContentHoverData, preference?: ContentWidgetPositionPreference) { - const widgetPosition: IContentWidgetPosition = { + this._contentPosition = { position: visibleData.showAtPosition, secondaryPosition: visibleData.showAtSecondaryPosition, positionAffinity: visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, preference: [preference ?? ContentWidgetPositionPreference.ABOVE] }; - this._contentPosition = widgetPosition; } public showAt(node: DocumentFragment, visibleData: ContentHoverData): void { From 3ab9cbc12029e1ff329586c77c79e6729c5adb5d Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 15:55:39 +0200 Subject: [PATCH 70/72] simplfying the code --- src/vs/editor/contrib/hover/browser/contentHover.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index 54dfa2ff2524d..f7f33312afd80 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -732,9 +732,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor - if (!this.findPersistedSize()) { - this.onContentsChanged(); - } + this.onContentsChanged(); if (visibleData.stoleFocus) { this._hoverWidget.containerDomNode.focus(); } From b595dd86896913c8fdfc5a71e4b390a344135ea9 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 16:27:00 +0200 Subject: [PATCH 71/72] renaming the variables --- .../contrib/hover/browser/contentHover.ts | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index f7f33312afd80..b7b41644d7c44 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -294,7 +294,7 @@ export class ContentHoverController extends Disposable { })); } - this._widget.showAt(fragment, new ContentHoverData( + this._widget.showAt(fragment, new HoverData( colorPicker, showAtPosition, showAtSecondaryPosition, @@ -428,7 +428,7 @@ class FilteredHoverResult extends HoverResult { } } -class ContentHoverData { +class HoverData { public closestMouseDistance: number | undefined = undefined; @@ -455,19 +455,19 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW public static ID = 'editor.contrib.resizableContentHoverWidget'; private _disposableStore = new DisposableStore(); - private _visibleData: ContentHoverData | undefined; - private _renderingAbove: ContentWidgetPositionPreference | undefined; + private _hoverData: HoverData | undefined; + private _positionPreference: ContentWidgetPositionPreference | undefined; private readonly _hoverWidget: HoverWidget = this._disposableStore.add(new HoverWidget()); private readonly _hoverVisibleKey: IContextKey; private readonly _hoverFocusedKey: IContextKey; public get isColorPickerVisible(): boolean { - return Boolean(this._visibleData?.colorPicker); + return Boolean(this._hoverData?.colorPicker); } public get isVisibleFromKeyboard(): boolean { - return (this._visibleData?.source === HoverStartSource.Keyboard); + return (this._hoverData?.source === HoverStartSource.Keyboard); } public get isVisible(): boolean { @@ -498,13 +498,13 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._disposableStore.add(focusTracker.onDidBlur(() => { this._hoverFocusedKey.set(false); })); - this._setVisibleData(undefined); + this._setHoverData(undefined); this._layout(); } public override dispose(): void { super.dispose(); - this._visibleData?.disposables.dispose(); + this._hoverData?.disposables.dispose(); this._disposableStore.dispose(); this._editor.removeContentWidget(this); } @@ -563,7 +563,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const width = size.width - 2 * SASH_WIDTH_MINUS_BORDER; const height = size.height - 2 * SASH_WIDTH_MINUS_BORDER; this._setHoverWidgetDimensions(width, height); - // measure if has horizontal scorllbar after setting the dimensions + // measure if widget has horizontal scrollbar after setting the dimensions if (this._hasHorizontalScrollbar()) { this._adjustContentsBottomPadding(); this._setContentsDomNodeDimensions(width, height - SCROLLBAR_WIDTH); @@ -571,9 +571,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _setResizableNodeMaxDimensions() { - const maxRenderingWidth = this._findMaximumRenderingWidth(); - const maxRenderingHeight = this._findMaximumRenderingHeight(); - this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth ?? Infinity, maxRenderingHeight ?? Infinity); + const maxRenderingWidth = this._findMaximumRenderingWidth() ?? Infinity; + const maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity; + this._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight); } override _resize(size: dom.Dimension) { @@ -584,11 +584,11 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } private _findAvailableSpaceVertically(): number | undefined { - if (!this._visibleData?.showAtPosition) { + const position = this._hoverData?.showAtPosition; + if (!position) { return; } - const position = this._visibleData.showAtPosition; - return this._renderingAbove === ContentWidgetPositionPreference.ABOVE ? this._availableVerticalSpaceAbove(position) : this._availableVerticalSpaceBelow(position); + return this._positionPreference === ContentWidgetPositionPreference.ABOVE ? this._availableVerticalSpaceAbove(position) : this._availableVerticalSpaceBelow(position); } private _findAvailableSpaceHorizontally(): number | undefined { @@ -621,25 +621,25 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW } public isMouseGettingCloser(posx: number, posy: number): boolean { - if (!this._visibleData) { + if (!this._hoverData) { return false; } - if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { - this._visibleData.initialMousePosX = posx; - this._visibleData.initialMousePosY = posy; + if (typeof this._hoverData.initialMousePosX === 'undefined' || typeof this._hoverData.initialMousePosY === 'undefined') { + this._hoverData.initialMousePosX = posx; + this._hoverData.initialMousePosY = posy; return false; } const widgetRect = dom.getDomNodePagePosition(this.getDomNode()); - if (typeof this._visibleData.closestMouseDistance === 'undefined') { - this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); + if (typeof this._hoverData.closestMouseDistance === 'undefined') { + this._hoverData.closestMouseDistance = computeDistanceFromPointToRectangle(this._hoverData.initialMousePosX, this._hoverData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); - if (distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { + if (distance > this._hoverData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } - this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); + this._hoverData.closestMouseDistance = Math.min(this._hoverData.closestMouseDistance, distance); return true; } @@ -647,12 +647,12 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._position = position; } - private _setVisibleData(visibleData: ContentHoverData | undefined): void { - this._setWidgetPosition(visibleData?.showAtPosition); - this._visibleData?.disposables.dispose(); - this._visibleData = visibleData; - this._hoverVisibleKey.set(!!visibleData); - this._hoverWidget.containerDomNode.classList.toggle('hidden', !visibleData); + private _setHoverData(hoverData: HoverData | undefined): void { + this._setWidgetPosition(hoverData?.showAtPosition); + this._hoverData?.disposables.dispose(); + this._hoverData = hoverData; + this._hoverVisibleKey.set(!!hoverData); + this._hoverWidget.containerDomNode.classList.toggle('hidden', !hoverData); } private _layout(): void { @@ -694,63 +694,61 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._setContentsDomNodeMaxDimensions(width, height); } - private _render(node: DocumentFragment, visibleData: ContentHoverData) { + private _render(node: DocumentFragment, hoverData: HoverData) { if (!this._hoverVisibleKey.get()) { this._editor.addContentWidget(this); } - this._setVisibleData(visibleData); + this._setHoverData(hoverData); this._updateFont(); this._updateContent(node); this._updateContentsDomNodeMaxDimensions(); - if (!this.findPersistedSize()) { - this.onContentsChanged(); - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); - } + this.onContentsChanged(); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this._editor.render(); } - private _setContentPosition(visibleData: ContentHoverData, preference?: ContentWidgetPositionPreference) { + private _setContentPosition(hoverData: HoverData, preference?: ContentWidgetPositionPreference) { this._contentPosition = { - position: visibleData.showAtPosition, - secondaryPosition: visibleData.showAtSecondaryPosition, - positionAffinity: visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, + position: hoverData.showAtPosition, + secondaryPosition: hoverData.showAtSecondaryPosition, + positionAffinity: hoverData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined, preference: [preference ?? ContentWidgetPositionPreference.ABOVE] }; } - public showAt(node: DocumentFragment, visibleData: ContentHoverData): void { + public showAt(node: DocumentFragment, hoverData: HoverData): void { if (!this._editor || !this._editor.hasModel()) { return; } - this._setContentPosition(visibleData); - this._render(node, visibleData); + this._setContentPosition(hoverData); + this._render(node, hoverData); const widgetHeight = this._getWidgetHeight(); - const widgetPosition = visibleData.showAtPosition; - this._renderingAbove = this._findRenderingPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE; - this._setContentPosition(visibleData, this._renderingAbove); + const widgetPosition = hoverData.showAtPosition; + this._positionPreference = this._findRenderingPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE; + this._setContentPosition(hoverData, this._positionPreference); // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor this.onContentsChanged(); - if (visibleData.stoleFocus) { + if (hoverData.stoleFocus) { this._hoverWidget.containerDomNode.focus(); } - visibleData.colorPicker?.layout(); + hoverData.colorPicker?.layout(); } public hide(): void { + if (!this._hoverData) { + return; + } + this._setHoverData(undefined); this._resizableNode.maxSize = new dom.Dimension(Infinity, Infinity); this._resizableNode.clearSashHoverState(); this._editor.removeContentWidget(this); - if (this._visibleData) { - const stoleFocus = this._visibleData.stoleFocus; - this._setVisibleData(undefined); - this._hoverFocusedKey.set(false); - this._editor.layoutContentWidget(this); - if (stoleFocus) { - this._editor.focus(); - } + this._hoverFocusedKey.set(false); + this._editor.layoutContentWidget(this); + if (this._hoverData.stoleFocus) { + this._editor.focus(); } } @@ -760,8 +758,9 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const persistedSize = this.findPersistedSize(); // Suppose a persisted size is defined if (persistedSize) { - width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - 2 * SASH_WIDTH_MINUS_BORDER); - height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - 2 * SASH_WIDTH_MINUS_BORDER); + const totalBorderWidth = 2 * SASH_WIDTH_MINUS_BORDER; + width = Math.min(this._findAvailableSpaceHorizontally() ?? Infinity, persistedSize.width - totalBorderWidth); + height = Math.min(this._findAvailableSpaceVertically() ?? Infinity, persistedSize.height - totalBorderWidth); } else { // Added because otherwise the initial size of the hover content is smaller than should be const layoutInfo = this._editor.getLayoutInfo(); @@ -791,7 +790,8 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW const containerDomNode = this._hoverWidget.containerDomNode; const clientHeight = containerDomNode.clientHeight; const clientWidth = containerDomNode.clientWidth; - this._resizableNode.layout(clientHeight + 2 * SASH_WIDTH_MINUS_BORDER, clientWidth + 2 * SASH_WIDTH_MINUS_BORDER); + const totalBorderWidth = 2 * SASH_WIDTH_MINUS_BORDER; + this._resizableNode.layout(clientHeight + totalBorderWidth, clientWidth + totalBorderWidth); this._setContainerAbsolutePosition(SASH_WIDTH_MINUS_BORDER - 1, SASH_WIDTH_MINUS_BORDER - 1); if (this._hasHorizontalScrollbar()) { this._adjustContentsBottomPadding(); From 8220e28ddb4c059185b0c0cc94bf145d87a7891e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Fri, 16 Jun 2023 16:42:36 +0200 Subject: [PATCH 72/72] making the code more clear --- .../contrib/hover/browser/contentHover.ts | 4 +-- src/vs/editor/contrib/hover/browser/hover.ts | 2 +- .../hover/browser/resizableContentWidget.ts | 29 +++++-------------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index b7b41644d7c44..515c4f64373fc 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -80,7 +80,7 @@ export class ContentHoverController extends Disposable { * Returns true if the hover shows now or will show. */ public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { - if (this._widget.resizing) { + if (this._widget.isResizing) { return true; } const anchorCandidates: HoverAnchor[] = []; @@ -725,7 +725,7 @@ export class ResizableHoverWidget extends MultiplePersistedSizeResizableContentW this._render(node, hoverData); const widgetHeight = this._getWidgetHeight(); const widgetPosition = hoverData.showAtPosition; - this._positionPreference = this._findRenderingPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE; + this._positionPreference = this._findPositionPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE; this._setContentPosition(hoverData, this._positionPreference); // See https://github.com/microsoft/vscode/issues/140339 diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index f78e27bb019c9..cc90e8fabacd2 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -222,7 +222,7 @@ export class ModesHoverController implements IEditorContribution { this._hoverClicked = false; this._glyphWidget?.hide(); - if (!this._contentWidget?.widget.resizing) { + if (!this._contentWidget?.widget.isResizing) { this._contentWidget?.hide(); } } diff --git a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts index 5487115403b06..c053517ef7c6d 100644 --- a/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts +++ b/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts @@ -21,39 +21,32 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg readonly allowEditorOverflow: boolean = true; readonly suppressMouseDown: boolean = false; - protected readonly _contentNode: HTMLDivElement; protected readonly _resizableNode = this._register(new ResizableHTMLElement()); protected _contentPosition: IContentWidgetPosition | null = null; - private _resizing: boolean = false; + private _isResizing: boolean = false; constructor( protected readonly _editor: ICodeEditor, _initialSize: dom.IDimension = new dom.Dimension(10, 10) ) { super(); - this._contentNode = document.createElement('div'); - this._contentNode.style.width = `${_initialSize.width}px`; - this._contentNode.style.height = `${_initialSize.height}px`; this._resizableNode.domNode.style.position = 'absolute'; - this._resizableNode.domNode.appendChild(this._contentNode); this._resizableNode.minSize = new dom.Dimension(10, 10); this._resizableNode.enableSashes(true, true, true, true); this._resizableNode.layout(_initialSize.height, _initialSize.width); this._register(this._resizableNode.onDidResize(e => { - this._contentNode.style.width = `${e.dimension.width}px`; - this._contentNode.style.height = `${e.dimension.height}px`; if (e.done) { - this._resizing = false; + this._isResizing = false; } })); this._register(this._resizableNode.onDidWillResize(() => { - this._resizing = true; + this._isResizing = true; })); } - get resizing() { - return this._resizing; + get isResizing() { + return this._isResizing; } abstract getId(): string; @@ -68,11 +61,8 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg protected _availableVerticalSpaceAbove(position: IPosition): number | undefined { const editorDomNode = this._editor.getDomNode(); - if (!editorDomNode) { - return; - } const mouseBox = this._editor.getScrolledVisiblePosition(position); - if (!mouseBox) { + if (!editorDomNode || !mouseBox) { return; } const editorBox = dom.getDomNodePagePosition(editorDomNode); @@ -81,11 +71,8 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg protected _availableVerticalSpaceBelow(position: IPosition): number | undefined { const editorDomNode = this._editor.getDomNode(); - if (!editorDomNode) { - return; - } const mouseBox = this._editor.getScrolledVisiblePosition(position); - if (!mouseBox) { + if (!editorDomNode || !mouseBox) { return; } const editorBox = dom.getDomNodePagePosition(editorDomNode); @@ -94,7 +81,7 @@ abstract class ResizableContentWidget extends Disposable implements IContentWidg return bodyBox.height - mouseBottom; } - protected _findRenderingPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { + protected _findPositionPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined { const maxHeightBelow = Math.min(this._availableVerticalSpaceBelow(showAtPosition) ?? Infinity, widgetHeight); const maxHeightAbove = Math.min(this._availableVerticalSpaceAbove(showAtPosition) ?? Infinity, widgetHeight); const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), widgetHeight);