diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 9f21950587b..ef6ecaf5a0f 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -132,10 +132,11 @@ export interface IContentWidgetPosition { */ position: IPosition | null; /** - * Optionally, a range can be provided to further - * define the position of the content widget. + * Optionally, a secondary position can be provided to further + * define the position of the content widget. The secondary position + * must have the same line number as the primary position. */ - range?: IRange | null; + secondaryPosition?: IPosition | null; /** * Placement preference for position, in order of preference. */ diff --git a/src/vs/editor/browser/view.ts b/src/vs/editor/browser/view.ts index 6ee27a31b3f..ec7b39e9028 100644 --- a/src/vs/editor/browser/view.ts +++ b/src/vs/editor/browser/view.ts @@ -37,7 +37,6 @@ import { SelectionsOverlay } from 'vs/editor/browser/viewParts/selections/select import { ViewCursors } from 'vs/editor/browser/viewParts/viewCursors/viewCursors'; import { ViewZones } from 'vs/editor/browser/viewParts/viewZones/viewZones'; import { Position } from 'vs/editor/common/core/position'; -import { Range } from 'vs/editor/common/core/range'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration'; import { RenderingContext } from 'vs/editor/browser/view/renderingContext'; @@ -502,15 +501,13 @@ export class View extends ViewEventHandler { } public layoutContentWidget(widgetData: IContentWidgetData): void { - let newRange = widgetData.position ? widgetData.position.range || null : null; - if (newRange === null) { - const newPosition = widgetData.position ? widgetData.position.position : null; - if (newPosition !== null) { - newRange = new Range(newPosition.lineNumber, newPosition.column, newPosition.lineNumber, newPosition.column); - } - } - const newPreference = widgetData.position ? widgetData.position.preference : null; - this._contentWidgets.setWidgetPosition(widgetData.widget, newRange, newPreference, widgetData.position?.positionAffinity ?? null); + this._contentWidgets.setWidgetPosition( + widgetData.widget, + widgetData.position?.position ?? null, + widgetData.position?.secondaryPosition ?? null, + widgetData.position?.preference ?? null, + widgetData.position?.positionAffinity ?? null + ); this._scheduleRender(); } diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 6ede41f7f92..cf5347e25ce 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -7,28 +7,15 @@ import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { ContentWidgetPositionPreference, IContentWidget } from 'vs/editor/browser/editorBrowser'; import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart'; -import { IRange, Range } from 'vs/editor/common/core/range'; -import { Constants } from 'vs/base/common/uint'; -import { HorizontalRange, LineVisibleRanges, RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext'; +import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext'; import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; import * as viewEvents from 'vs/editor/common/viewEvents'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { IDimension } from 'vs/editor/common/core/dimension'; import { PositionAffinity } from 'vs/editor/common/model'; - - -class Coordinate { - _coordinateBrand: void = undefined; - - public readonly top: number; - public readonly left: number; - - constructor(top: number, left: number) { - this.top = top; - this.left = left; - } -} +import { IPosition, Position } from 'vs/editor/common/core/position'; +import { IViewModel } from 'vs/editor/common/viewModel'; export class ViewContentWidgets extends ViewPart { @@ -113,9 +100,9 @@ export class ViewContentWidgets extends ViewPart { this.setShouldRender(); } - public setWidgetPosition(widget: IContentWidget, range: IRange | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void { + public setWidgetPosition(widget: IContentWidget, primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void { const myWidget = this._widgets[widget.getId()]; - myWidget.setPosition(range, preference, affinity); + myWidget.setPosition(primaryAnchor, secondaryAnchor, preference, affinity); this.setShouldRender(); } @@ -166,11 +153,11 @@ export class ViewContentWidgets extends ViewPart { interface IBoxLayoutResult { fitsAbove: boolean; aboveTop: number; - aboveLeft: number; fitsBelow: boolean; belowTop: number; - belowLeft: number; + + left: number; } interface IRenderData { @@ -193,9 +180,9 @@ class Widget { private _contentLeft: number; private _lineHeight: number; - private _range: IRange | null; + private _primaryAnchor: PositionPair = new PositionPair(null, null); + private _secondaryAnchor: PositionPair = new PositionPair(null, null); private _affinity: PositionAffinity | null; - private _viewRange: Range | null; private _preference: ContentWidgetPositionPreference[] | null; private _cachedDomNodeOffsetWidth: number; private _cachedDomNodeOffsetHeight: number; @@ -222,8 +209,6 @@ class Widget { this._contentLeft = layoutInfo.contentLeft; this._lineHeight = options.get(EditorOption.lineHeight); - this._range = null; - this._viewRange = null; this._affinity = null; this._preference = []; this._cachedDomNodeOffsetWidth = -1; @@ -251,20 +236,25 @@ class Widget { } public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): void { - this._setPosition(this._range, this._affinity); + this._setPosition(this._affinity, this._primaryAnchor.modelPosition, this._secondaryAnchor.modelPosition); } - private _setPosition(range: IRange | null, affinity: PositionAffinity | null): void { - this._range = range; - this._viewRange = null; + private _setPosition(affinity: PositionAffinity | null, primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null): void { this._affinity = affinity; + this._primaryAnchor = getValidPositionPair(primaryAnchor, this._context.viewModel, this._affinity); + this._secondaryAnchor = getValidPositionPair(secondaryAnchor, this._context.viewModel, this._affinity); - if (this._range) { - // Do not trust that widgets give a valid position - const validModelRange = this._context.viewModel.model.validateRange(this._range); - if (this._context.viewModel.coordinatesConverter.modelPositionIsVisible(validModelRange.getStartPosition()) || this._context.viewModel.coordinatesConverter.modelPositionIsVisible(validModelRange.getEndPosition())) { - this._viewRange = this._context.viewModel.coordinatesConverter.convertModelRangeToViewRange(validModelRange, this._affinity ?? undefined); + function getValidPositionPair(position: IPosition | null, viewModel: IViewModel, affinity: PositionAffinity | null): PositionPair { + if (!position) { + return new PositionPair(null, null); } + // Do not trust that widgets give a valid position + const validModelPosition = viewModel.model.validatePosition(position); + if (viewModel.coordinatesConverter.modelPositionIsVisible(validModelPosition)) { + const viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition, affinity ?? undefined); + return new PositionPair(position, viewPosition); + } + return new PositionPair(position, null); } } @@ -276,10 +266,10 @@ class Widget { ); } - public setPosition(range: IRange | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void { - this._setPosition(range, affinity); + public setPosition(primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void { + this._setPosition(affinity, primaryAnchor, secondaryAnchor); this._preference = preference; - if (this._viewRange && this._preference && this._preference.length > 0) { + if (this._primaryAnchor.viewPosition && this._preference && this._preference.length > 0) { // this content widget would like to be visible if possible // we change it from `display:none` to `display:block` even if it // might be outside the viewport such that we can measure its size @@ -292,15 +282,15 @@ class Widget { this._cachedDomNodeOffsetHeight = -1; } - private _layoutBoxInViewport(aboveAnchor: Coordinate, belowAnchor: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult { + private _layoutBoxInViewport(anchor: AnchorCoordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult { // Our visible box is split horizontally by the current line => 2 boxes // a) the box above the line - const aboveLineTop = aboveAnchor.top; + const aboveLineTop = anchor.top; const heightAvailableAboveLine = aboveLineTop; // b) the box under the line - const underLineTop = belowAnchor.top; + const underLineTop = anchor.top + anchor.height; const heightAvailableUnderLine = ctx.viewportHeight - underLineTop; const aboveTop = aboveLineTop - height; @@ -309,30 +299,15 @@ class Widget { const fitsBelow = (heightAvailableUnderLine >= height); // And its left - let actualAboveLeft = aboveAnchor.left; - let actualBelowLeft = belowAnchor.left; - if (actualAboveLeft + width > ctx.scrollLeft + ctx.viewportWidth) { - actualAboveLeft = ctx.scrollLeft + ctx.viewportWidth - width; + let left = anchor.left; + if (left + width > ctx.scrollLeft + ctx.viewportWidth) { + left = ctx.scrollLeft + ctx.viewportWidth - width; } - if (actualBelowLeft + width > ctx.scrollLeft + ctx.viewportWidth) { - actualBelowLeft = ctx.scrollLeft + ctx.viewportWidth - width; - } - if (actualAboveLeft < ctx.scrollLeft) { - actualAboveLeft = ctx.scrollLeft; - } - if (actualBelowLeft < ctx.scrollLeft) { - actualBelowLeft = ctx.scrollLeft; + if (left < ctx.scrollLeft) { + left = ctx.scrollLeft; } - return { - fitsAbove: fitsAbove, - aboveTop: aboveTop, - aboveLeft: actualAboveLeft, - - fitsBelow: fitsBelow, - belowTop: belowTop, - belowLeft: actualBelowLeft, - }; + return { fitsAbove, aboveTop, fitsBelow, belowTop, left }; } private _layoutHorizontalSegmentInPage(windowSize: dom.Dimension, domNodePosition: dom.IDomNodePagePosition, left: number, width: number): [number, number] { @@ -357,17 +332,16 @@ class Widget { return [left, absoluteLeft]; } - private _layoutBoxInPage(aboveAnchor: Coordinate, belowAnchor: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult | null { - const aboveTop = aboveAnchor.top - height; - const belowTop = belowAnchor.top; + private _layoutBoxInPage(anchor: AnchorCoordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult | null { + const aboveTop = anchor.top - height; + const belowTop = anchor.top + anchor.height; const domNodePosition = dom.getDomNodePagePosition(this._viewDomNode.domNode); const absoluteAboveTop = domNodePosition.top + aboveTop - window.scrollY; const absoluteBelowTop = domNodePosition.top + belowTop - window.scrollY; const windowSize = dom.getClientArea(document.body); - const [aboveLeft, absoluteAboveLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, aboveAnchor.left - ctx.scrollLeft + this._contentLeft, width); - const [belowLeft, absoluteBelowLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, belowAnchor.left - ctx.scrollLeft + this._contentLeft, width); + const [left, absoluteAboveLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, anchor.left - ctx.scrollLeft + this._contentLeft, width); // Leave some clearance to the top/bottom const TOP_PADDING = 22; @@ -380,21 +354,13 @@ class Widget { return { fitsAbove, aboveTop: Math.max(absoluteAboveTop, TOP_PADDING), - aboveLeft: absoluteAboveLeft, fitsBelow, belowTop: absoluteBelowTop, - belowLeft: absoluteBelowLeft + left: absoluteAboveLeft }; } - return { - fitsAbove, - aboveTop, - aboveLeft, - fitsBelow, - belowTop, - belowLeft - }; + return { fitsAbove, aboveTop, fitsBelow, belowTop, left }; } private _prepareRenderWidgetAtExactPositionOverflowing(topLeft: Coordinate): Coordinate { @@ -402,43 +368,47 @@ class Widget { } /** - * Compute the above and below anchors + * Compute the coordinates above and below the primary and secondary anchors. + * The content widget *must* touch the primary anchor. + * The content widget should touch if possible the secondary anchor. */ - private _getAnchors(ctx: RenderingContext): [Coordinate | null, Coordinate | null] { - if (!this._viewRange) { - return [null, null]; - } + private _getAnchorsCoordinates(ctx: RenderingContext): { primary: AnchorCoordinate | null; secondary: AnchorCoordinate | null } { + const primary = getCoordinates(this._primaryAnchor.viewPosition, this._affinity, this._lineHeight); + const secondaryViewPosition = (this._secondaryAnchor.viewPosition?.lineNumber === this._primaryAnchor.viewPosition?.lineNumber ? this._secondaryAnchor.viewPosition : null); + const secondary = getCoordinates(secondaryViewPosition, this._affinity, this._lineHeight); + return { primary, secondary }; - const visibleRangesForRange = ctx.linesVisibleRangesForRange(this._viewRange, false); - const aboveAnchor = getCoordinate(LineVisibleRanges.firstLine(visibleRangesForRange), this._affinity, this._viewRange.startColumn, 0); - const belowAnchor = getCoordinate(LineVisibleRanges.lastLine(visibleRangesForRange), this._affinity, this._viewRange.startColumn, this._lineHeight); - return [aboveAnchor, belowAnchor]; - - function getCoordinate(line: LineVisibleRanges | null, affinity: PositionAffinity | null, startColumn: number, deltaTop: number): Coordinate | null { - if (!line) { + function getCoordinates(position: Position | null, affinity: PositionAffinity | null, lineHeight: number): AnchorCoordinate | null { + if (!position) { return null; } - const left = getLeft(line.ranges, affinity, startColumn); - const top = ctx.getVerticalOffsetForLineNumber(line.lineNumber) - ctx.scrollTop; - return new Coordinate(top + deltaTop, left); + + const horizontalPosition = ctx.visibleRangeForPosition(position); + if (!horizontalPosition) { + return null; + } + + // Left-align widgets that should appear :before content + const left = (position.column === 1 && affinity === PositionAffinity.LeftOfInjectedText ? 0 : horizontalPosition.left); + const top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.scrollTop; + return new AnchorCoordinate(top, left, lineHeight); + } + } + + private _reduceAnchorCoordinates(primary: AnchorCoordinate, secondary: AnchorCoordinate | null, width: number): AnchorCoordinate { + if (!secondary) { + return primary; } - /** - * Return the left-most position from `ranges`. - */ - function getLeft(ranges: HorizontalRange[], affinity: PositionAffinity | null, startColumn: number): number { - // Left-align widgets that should appear :before content - if (startColumn === 1 && affinity === PositionAffinity.LeftOfInjectedText) { - return 0; - } - let result = Constants.MAX_SAFE_SMALL_INTEGER; - for (const range of ranges) { - if (range.left < result) { - result = range.left; - } - } - return result; + const fontInfo = this._context.configuration.options.get(EditorOption.fontInfo); + + let left = secondary.left; + if (left < primary.left) { + left = Math.max(left, primary.left - width + fontInfo.typicalFullwidthCharacterWidth); + } else { + left = Math.min(left, primary.left + width - fontInfo.typicalFullwidthCharacterWidth); } + return new AnchorCoordinate(primary.top, left, primary.height); } private _prepareRenderWidget(ctx: RenderingContext): IRenderData | null { @@ -446,8 +416,8 @@ class Widget { return null; } - const [aboveAnchor, belowAnchor] = this._getAnchors(ctx); - if (!aboveAnchor || !belowAnchor) { + const { primary, secondary } = this._getAnchorsCoordinates(ctx); + if (!primary) { return null; } @@ -468,11 +438,13 @@ class Widget { } } + const anchor = this._reduceAnchorCoordinates(primary, secondary, this._cachedDomNodeOffsetWidth); + let placement: IBoxLayoutResult | null; if (this.allowEditorOverflow) { - placement = this._layoutBoxInPage(aboveAnchor, belowAnchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx); + placement = this._layoutBoxInPage(anchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx); } else { - placement = this._layoutBoxInViewport(aboveAnchor, belowAnchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx); + placement = this._layoutBoxInViewport(anchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx); } // Do two passes, first for perfect fit, second picks first option @@ -485,7 +457,7 @@ class Widget { return null; } if (pass === 2 || placement.fitsAbove) { - return { coordinate: new Coordinate(placement.aboveTop, placement.aboveLeft), position: ContentWidgetPositionPreference.ABOVE }; + return { coordinate: new Coordinate(placement.aboveTop, placement.left), position: ContentWidgetPositionPreference.ABOVE }; } } else if (pref === ContentWidgetPositionPreference.BELOW) { if (!placement) { @@ -493,13 +465,13 @@ class Widget { return null; } if (pass === 2 || placement.fitsBelow) { - return { coordinate: new Coordinate(placement.belowTop, placement.belowLeft), position: ContentWidgetPositionPreference.BELOW }; + return { coordinate: new Coordinate(placement.belowTop, placement.left), position: ContentWidgetPositionPreference.BELOW }; } } else { if (this.allowEditorOverflow) { - return { coordinate: this._prepareRenderWidgetAtExactPositionOverflowing(aboveAnchor), position: ContentWidgetPositionPreference.EXACT }; + return { coordinate: this._prepareRenderWidgetAtExactPositionOverflowing(new Coordinate(anchor.top, anchor.left)), position: ContentWidgetPositionPreference.EXACT }; } else { - return { coordinate: aboveAnchor, position: ContentWidgetPositionPreference.EXACT }; + return { coordinate: new Coordinate(anchor.top, anchor.left), position: ContentWidgetPositionPreference.EXACT }; } } } @@ -512,11 +484,11 @@ class Widget { * On this first pass, we ensure that the content widget (if it is in the viewport) has the max width set correctly. */ public onBeforeRender(viewportData: ViewportData): void { - if (!this._viewRange || !this._preference) { + if (!this._primaryAnchor.viewPosition || !this._preference) { return; } - if (this._viewRange.endLineNumber < viewportData.startLineNumber || this._viewRange.startLineNumber > viewportData.endLineNumber) { + if (this._primaryAnchor.viewPosition.lineNumber < viewportData.startLineNumber || this._primaryAnchor.viewPosition.lineNumber > viewportData.endLineNumber) { // Outside of viewport return; } @@ -564,6 +536,32 @@ class Widget { } } +class PositionPair { + constructor( + public readonly modelPosition: IPosition | null, + public readonly viewPosition: Position | null + ) { } +} + +class Coordinate { + _coordinateBrand: void = undefined; + + constructor( + public readonly top: number, + public readonly left: number + ) { } +} + +class AnchorCoordinate { + _anchorCoordinateBrand: void = undefined; + + constructor( + public readonly top: number, + public readonly left: number, + public readonly height: number + ) { } +} + function safeInvoke any>(fn: T, thisArg: ThisParameterType, ...args: Parameters): ReturnType | null { try { return fn.call(thisArg, ...args); diff --git a/src/vs/editor/contrib/hover/browser/contentHover.ts b/src/vs/editor/contrib/hover/browser/contentHover.ts index e0f2246f5a6..6929f34486c 100644 --- a/src/vs/editor/contrib/hover/browser/contentHover.ts +++ b/src/vs/editor/contrib/hover/browser/contentHover.ts @@ -24,7 +24,6 @@ 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 { Constants } from 'vs/base/common/uint'; const $ = dom.$; @@ -241,7 +240,7 @@ export class ContentHoverController extends Disposable { } private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void { - const { showAtPosition, showAtRange, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages); + const { showAtPosition, showAtSecondaryPosition, highlightRange } = ContentHoverController.computeHoverRanges(this._editor, anchor.range, messages); const disposables = new DisposableStore(); const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService)); @@ -284,7 +283,7 @@ export class ContentHoverController extends Disposable { this._widget.showAt(fragment, new ContentHoverVisibleData( colorPicker, showAtPosition, - showAtRange, + showAtSecondaryPosition, this._editor.getOption(EditorOption.hover).above, this._computer.shouldFocus, isBeforeContent, @@ -304,21 +303,17 @@ export class ContentHoverController extends Disposable { public static computeHoverRanges(editor: ICodeEditor, anchorRange: Range, messages: IHoverPart[]) { let startColumnBoundary = 1; - let endColumnBoundary = Constants.MAX_SAFE_SMALL_INTEGER; if (editor.hasModel()) { // Ensure the range is on the current view line const viewModel = editor._getViewModel(); const coordinatesConverter = viewModel.coordinatesConverter; const anchorViewRange = coordinatesConverter.convertModelRangeToViewRange(anchorRange); const anchorViewRangeStart = new Position(anchorViewRange.startLineNumber, viewModel.getLineMinColumn(anchorViewRange.startLineNumber)); - const anchorViewRangeEnd = new Position(anchorViewRange.endLineNumber, viewModel.getLineMaxColumn(anchorViewRange.endLineNumber)); startColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeStart).column; - endColumnBoundary = coordinatesConverter.convertViewPositionToModelPosition(anchorViewRangeEnd).column; } // The anchor range is always on a single line const anchorLineNumber = anchorRange.startLineNumber; let renderStartColumn = anchorRange.startColumn; - let renderEndColumn = anchorRange.endColumn; let highlightRange: Range = messages[0].range; let forceShowAtRange: Range | null = null; @@ -327,7 +322,6 @@ export class ContentHoverController extends Disposable { if (msg.range.startLineNumber === anchorLineNumber && msg.range.endLineNumber === anchorLineNumber) { // this message has a range that is completely sitting on the line of the anchor renderStartColumn = Math.max(Math.min(renderStartColumn, msg.range.startColumn), startColumnBoundary); - renderEndColumn = Math.min(Math.max(renderEndColumn, msg.range.endColumn), endColumnBoundary); } if (msg.forceShowAtRange) { forceShowAtRange = msg.range; @@ -335,8 +329,8 @@ export class ContentHoverController extends Disposable { } return { - showAtPosition: forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorRange.startLineNumber, renderStartColumn), - showAtRange: forceShowAtRange ? forceShowAtRange : new Range(anchorLineNumber, renderStartColumn, anchorLineNumber, renderEndColumn), + showAtPosition: forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, anchorRange.startColumn), + showAtSecondaryPosition: forceShowAtRange ? forceShowAtRange.getStartPosition() : new Position(anchorLineNumber, renderStartColumn), highlightRange }; } @@ -382,7 +376,7 @@ class ContentHoverVisibleData { constructor( public readonly colorPicker: IEditorHoverColorPickerWidget | null, public readonly showAtPosition: Position, - public readonly showAtRange: Range, + public readonly showAtSecondaryPosition: Position, public readonly preferAbove: boolean, public readonly stoleFocus: boolean, public readonly isBeforeContent: boolean, @@ -463,7 +457,7 @@ export class ContentHoverWidget extends Disposable implements IContentWidget { return { position: this._visibleData.showAtPosition, - range: this._visibleData.showAtRange, + secondaryPosition: this._visibleData.showAtSecondaryPosition, preference: ( preferAbove ? [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW] diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 555ee5b0659..744e14bf8d6 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4780,10 +4780,11 @@ declare namespace monaco.editor { */ position: IPosition | null; /** - * Optionally, a range can be provided to further - * define the position of the content widget. + * Optionally, a secondary position can be provided to further + * define the position of the content widget. The secondary position + * must have the same line number as the primary position. */ - range?: IRange | null; + secondaryPosition?: IPosition | null; /** * Placement preference for position, in order of preference. */