Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support dedicated lane for breakpoint decorations #180013

Merged
merged 9 commits into from
Apr 19, 2023
12 changes: 11 additions & 1 deletion src/vs/editor/browser/config/editorConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class EditorConfiguration extends Disposable implements IEditorConfigurat
private _viewLineCount: number = 1;
private _lineNumbersDigitCount: number = 1;
private _reservedHeight: number = 0;
private _glyphMarginDecorationLaneCount: number = 1;

private readonly _computeOptionsMemory: ComputeOptionsMemory = new ComputeOptionsMemory();
/**
Expand Down Expand Up @@ -117,7 +118,8 @@ export class EditorConfiguration extends Disposable implements IEditorConfigurat
emptySelectionClipboard: partialEnv.emptySelectionClipboard,
pixelRatio: partialEnv.pixelRatio,
tabFocusMode: TabFocus.getTabFocusMode(TabFocusContext.Editor),
accessibilitySupport: partialEnv.accessibilitySupport
accessibilitySupport: partialEnv.accessibilitySupport,
glyphMarginDecorationLaneCount: this._glyphMarginDecorationLaneCount
};
return EditorOptionsUtil.computeOptions(this._validatedOptions, env);
}
Expand Down Expand Up @@ -193,6 +195,14 @@ export class EditorConfiguration extends Disposable implements IEditorConfigurat
this._reservedHeight = reservedHeight;
this._recomputeOptions();
}

public setGlyphMarginDecorationLaneCount(decorationLaneCount: number): void {
if (this._glyphMarginDecorationLaneCount === decorationLaneCount) {
return;
}
this._glyphMarginDecorationLaneCount = decorationLaneCount;
this._recomputeOptions();
}
}

function digitCount(n: number): number {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ export const _CSS_MAP: { [prop: string]: string } = {
cursor: 'cursor:{0};',
letterSpacing: 'letter-spacing:{0};',

gutterIconPath: 'background:{0} center center no-repeat;',
gutterIconPath: 'background:{0} no-repeat;',
gutterIconSize: 'background-size:{0};',

contentText: 'content:\'{0}\';',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}
91 changes: 71 additions & 20 deletions src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,60 @@ export class DecorationToRender {
public endLineNumber: number;
public className: string;
public readonly zIndex: number;
public readonly decorationLane: number;

constructor(startLineNumber: number, endLineNumber: number, className: string, zIndex?: number) {
constructor(startLineNumber: number, endLineNumber: number, className: string, zIndex?: number, decorationLane?: number) {
this.startLineNumber = +startLineNumber;
this.endLineNumber = +endLineNumber;
this.className = String(className);
this.zIndex = zIndex ?? 0;
this.decorationLane = decorationLane ?? 1;
}
}

export class RenderedDecoration {
constructor(
public readonly className: string,
public readonly zIndex: number,
) { }
}

export class LineRenderedDecorations {

private readonly lanes: RenderedDecoration[][] = [];

public add(lane: number, decoration: RenderedDecoration) {
while (lane >= this.lanes.length) {
this.lanes.push([]);
}
this.lanes[lane].push(decoration);
}

public getLaneDecorations(laneIndex: number): RenderedDecoration[] {
if (laneIndex < this.lanes.length) {
return this.lanes[laneIndex];
}
return [];
}

public isEmpty(): boolean {
for (const lane of this.lanes) {
if (lane.length > 0) {
return false;
}
}
return true;
}
}

export abstract class DedupOverlay extends DynamicViewOverlay {

protected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[]): [string, number][][] {
protected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[], decorationLaneCount: number): LineRenderedDecorations[] {

const output: [string, number][][] = [];
const output: LineRenderedDecorations[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
const lineIndex = lineNumber - visibleStartLineNumber;
output[lineIndex] = [];
output[lineIndex] = new LineRenderedDecorations();
}

if (decorations.length === 0) {
Expand All @@ -59,6 +96,7 @@ export abstract class DedupOverlay extends DynamicViewOverlay {
const zIndex = d.zIndex;
let startLineIndex = Math.max(d.startLineNumber, visibleStartLineNumber) - visibleStartLineNumber;
const endLineIndex = Math.min(d.endLineNumber, visibleEndLineNumber) - visibleStartLineNumber;
const lane = Math.min(d.decorationLane, decorationLaneCount);

if (prevClassName === className) {
startLineIndex = Math.max(prevEndLineIndex + 1, startLineIndex);
Expand All @@ -69,7 +107,7 @@ export abstract class DedupOverlay extends DynamicViewOverlay {
}

for (let i = startLineIndex; i <= prevEndLineIndex; i++) {
output[i].push([className, zIndex]);
output[i].add(lane, new RenderedDecoration(className, zIndex));
}
}

Expand All @@ -84,6 +122,7 @@ export class GlyphMarginOverlay extends DedupOverlay {
private _glyphMargin: boolean;
private _glyphMarginLeft: number;
private _glyphMarginWidth: number;
private _glyphMarginDecorationLaneCount: number;
private _renderResult: string[] | null;

constructor(context: ViewContext) {
Expand All @@ -97,6 +136,7 @@ export class GlyphMarginOverlay extends DedupOverlay {
this._glyphMargin = options.get(EditorOption.glyphMargin);
this._glyphMarginLeft = layoutInfo.glyphMarginLeft;
this._glyphMarginWidth = layoutInfo.glyphMarginWidth;
this._glyphMarginDecorationLaneCount = layoutInfo.glyphMarginDecorationLaneCount;
this._renderResult = null;
this._context.addEventHandler(this);
}
Expand All @@ -117,6 +157,7 @@ export class GlyphMarginOverlay extends DedupOverlay {
this._glyphMargin = options.get(EditorOption.glyphMargin);
this._glyphMarginLeft = layoutInfo.glyphMarginLeft;
this._glyphMarginWidth = layoutInfo.glyphMarginWidth;
this._glyphMarginDecorationLaneCount = layoutInfo.glyphMarginDecorationLaneCount;
return true;
}
public override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {
Expand Down Expand Up @@ -151,8 +192,9 @@ export class GlyphMarginOverlay extends DedupOverlay {
const d = decorations[i];
const glyphMarginClassName = d.options.glyphMarginClassName;
const zIndex = d.options.zIndex;
const lane = d.options.glyphMargin?.position;
if (glyphMarginClassName) {
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName, zIndex);
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName, zIndex, lane);
}
}
return r;
Expand All @@ -167,31 +209,40 @@ export class GlyphMarginOverlay extends DedupOverlay {
const visibleStartLineNumber = ctx.visibleRange.startLineNumber;
const visibleEndLineNumber = ctx.visibleRange.endLineNumber;
const decorationsToRender = this._getDecorations(ctx);
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, decorationsToRender);
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, decorationsToRender, this._glyphMarginDecorationLaneCount);

const lineHeight = this._lineHeight.toString();
const left = this._glyphMarginLeft.toString();
const width = this._glyphMarginWidth.toString();
const common = '" style="left:' + left + 'px;width:' + width + 'px' + ';height:' + lineHeight + 'px;"></div>';
const common = '" style="width:' + width + 'px' + ';height:' + lineHeight + 'px;';

const output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
const lineIndex = lineNumber - visibleStartLineNumber;
const renderInfo = toRender[lineIndex];

if (renderInfo.length === 0) {
if (renderInfo.isEmpty()) {
output[lineIndex] = '';
} else {
// Sort decorations to render in descending order by zIndex
renderInfo.sort(([_, aIndex], [__, bIndex]) => {
return bIndex - aIndex;
});

output[lineIndex] = (
'<div class="cgmr codicon '
+ renderInfo[0][0]
+ common
);
let css = '';
for (let lane = 1; lane <= this._glyphMarginDecorationLaneCount; lane += 1) {
const decorations = renderInfo.getLaneDecorations(lane);
if (decorations.length === 0) {
continue;
}
decorations.sort((a, b) => {
// Sort decorations to render in descending order by zIndex
return b.zIndex - a.zIndex;
});
const winningDecoration: RenderedDecoration = decorations[0];
const left = (this._glyphMarginLeft + (lane - 1) * this._lineHeight).toString();
css += (
'<div class="cgmr codicon '
+ winningDecoration.className // TODO@joyceerhl Implement overflow for remaining decorations
+ common
+ 'left:' + left + 'px;"></div>'
);
}
output[lineIndex] = css;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class LinesDecorationsOverlay extends DedupOverlay {
public prepareRender(ctx: RenderingContext): void {
const visibleStartLineNumber = ctx.visibleRange.startLineNumber;
const visibleEndLineNumber = ctx.visibleRange.endLineNumber;
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx), 1);

const left = this._decorationsLeft.toString();
const width = this._decorationsWidth.toString();
Expand All @@ -100,10 +100,10 @@ export class LinesDecorationsOverlay extends DedupOverlay {
const output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
const lineIndex = lineNumber - visibleStartLineNumber;
const classNames = toRender[lineIndex];
const decorations = toRender[lineIndex].getLaneDecorations(1); // there is only one lane, see _render call above
let lineOutput = '';
for (let i = 0, len = classNames.length; i < len; i++) {
lineOutput += '<div class="cldr ' + classNames[i][0] + common;
for (const decoration of decorations) {
lineOutput += '<div class="cldr ' + decoration.className + common;
}
output[lineIndex] = lineOutput;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ export class MarginViewLineDecorationsOverlay extends DedupOverlay {
public prepareRender(ctx: RenderingContext): void {
const visibleStartLineNumber = ctx.visibleRange.startLineNumber;
const visibleEndLineNumber = ctx.visibleRange.endLineNumber;
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));
const toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx), 1);

const output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
const lineIndex = lineNumber - visibleStartLineNumber;
const classNames = toRender[lineIndex];
const decorations = toRender[lineIndex].getLaneDecorations(1); // there is only one lane, see _render call above
let lineOutput = '';
for (let i = 0, len = classNames.length; i < len; i++) {
lineOutput += '<div class="cmdr ' + classNames[i][0] + '" style=""></div>';
for (const decoration of decorations) {
lineOutput += '<div class="cmdr ' + decoration.className + '" style=""></div>';
}
output[lineIndex] = lineOutput;
}
Expand Down
4 changes: 4 additions & 0 deletions src/vs/editor/common/config/editorConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ export interface IEditorConfiguration extends IDisposable {
* Set reserved height above.
*/
setReservedHeight(reservedHeight: number): void;
/**
* Set the number of decoration lanes to be rendered in the glyph margin.
*/
setGlyphMarginDecorationLaneCount(decorationLaneCount: number): void;
}
13 changes: 11 additions & 2 deletions src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ export interface IEnvironmentalOptions {
readonly pixelRatio: number;
readonly tabFocusMode: boolean;
readonly accessibilitySupport: AccessibilitySupport;
readonly glyphMarginDecorationLaneCount: number;
}

/**
Expand Down Expand Up @@ -2063,6 +2064,11 @@ export interface EditorLayoutInfo {
*/
readonly glyphMarginWidth: number;

/**
* The number of decoration lanes to render in the glyph margin.
*/
readonly glyphMarginDecorationLaneCount: number;

/**
* Left position for the line numbers.
*/
Expand Down Expand Up @@ -2150,6 +2156,7 @@ export interface EditorLayoutInfoComputerEnv {
readonly typicalHalfwidthCharacterWidth: number;
readonly maxDigitWidth: number;
readonly pixelRatio: number;
readonly glyphMarginDecorationLaneCount: number;
}

/**
Expand Down Expand Up @@ -2217,7 +2224,8 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
lineNumbersDigitCount: env.lineNumbersDigitCount,
typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth,
maxDigitWidth: env.fontInfo.maxDigitWidth,
pixelRatio: env.pixelRatio
pixelRatio: env.pixelRatio,
glyphMarginDecorationLaneCount: env.glyphMarginDecorationLaneCount
});
}

Expand Down Expand Up @@ -2463,7 +2471,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.

let glyphMarginWidth = 0;
if (showGlyphMargin) {
glyphMarginWidth = lineHeight;
glyphMarginWidth = lineHeight * env.glyphMarginDecorationLaneCount;
}

let glyphMarginLeft = 0;
Expand Down Expand Up @@ -2531,6 +2539,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.

glyphMarginLeft: glyphMarginLeft,
glyphMarginWidth: glyphMarginWidth,
glyphMarginDecorationLaneCount: env.glyphMarginDecorationLaneCount,

lineNumbersLeft: lineNumbersLeft,
lineNumbersWidth: lineNumbersWidth,
Expand Down
24 changes: 22 additions & 2 deletions src/vs/editor/common/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ export enum OverviewRulerLane {
Full = 7
}

/**
* Vertical Lane in the glyph margin of the editor.
*/
export enum GlyphMarginLane {
Left = 1,
Right = 2
}

/**
* Position in the minimap to render the decoration.
*/
Expand All @@ -55,6 +63,13 @@ export interface IDecorationOptions {
darkColor?: string | ThemeColor;
}

export interface IModelDecorationGlyphMarginOptions {
/**
* The position in the glyph margin.
*/
position: GlyphMarginLane;
}

/**
* Options for rendering a model decoration in the overview ruler.
*/
Expand All @@ -66,11 +81,11 @@ export interface IModelDecorationOverviewRulerOptions extends IDecorationOptions
}

/**
* Options for rendering a model decoration in the overview ruler.
* Options for rendering a model decoration in the minimap.
*/
export interface IModelDecorationMinimapOptions extends IDecorationOptions {
/**
* The position in the overview ruler.
* The position in the minimap.
*/
position: MinimapPosition;
}
Expand Down Expand Up @@ -141,6 +156,11 @@ export interface IModelDecorationOptions {
* If set, the decoration will be rendered in the glyph margin with this CSS class name.
*/
glyphMarginClassName?: string | null;
/**
* If set and the decoration has {@link glyphMarginClassName} set, render this decoration
* with the specified {@link IModelDecorationGlyphMarginOptions} in the glyph margin.
*/
glyphMargin?: IModelDecorationGlyphMarginOptions | null;
/**
* If set, the decoration will be rendered in the lines decorations with this CSS class name.
*/
Expand Down
Loading