diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts
index 48707de51cb465e90c13bea3bb1b9bd25fe2d428..5f1f7ab106732fd4a2fc98f41d16aac5af2738f2 100644
--- a/src/vs/editor/browser/view/viewImpl.ts
+++ b/src/vs/editor/browser/view/viewImpl.ts
@@ -30,7 +30,9 @@ import { GlyphMarginOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyp
import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';
import { IndentGuidesOverlay } from 'vs/editor/browser/viewParts/indentGuides/indentGuides';
import { ViewLines } from 'vs/editor/browser/viewParts/lines/viewLines';
+import { Margin } from 'vs/editor/browser/viewParts/margin/margin';
import { LinesDecorationsOverlay } from 'vs/editor/browser/viewParts/linesDecorations/linesDecorations';
+import { MarginViewLineDecorationsOverlay } from 'vs/editor/browser/viewParts/marginDecorations/marginDecorations';
import { ViewOverlayWidgets } from 'vs/editor/browser/viewParts/overlayWidgets/overlayWidgets';
import { DecorationsOverviewRuler } from 'vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler';
import { OverviewRuler } from 'vs/editor/browser/viewParts/overviewRuler/overviewRuler';
@@ -237,9 +239,14 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
let marginViewOverlays = new MarginViewOverlays(this._context, this.layoutProvider);
this.viewParts.push(marginViewOverlays);
marginViewOverlays.addDynamicOverlay(new GlyphMarginOverlay(this._context));
+ marginViewOverlays.addDynamicOverlay(new MarginViewLineDecorationsOverlay(this._context));
marginViewOverlays.addDynamicOverlay(new LinesDecorationsOverlay(this._context));
marginViewOverlays.addDynamicOverlay(new LineNumbersOverlay(this._context));
+ let margin = new Margin(this._context, this.layoutProvider);
+ margin.domNode.appendChild(this.viewZones.marginDomNode);
+ margin.domNode.appendChild(marginViewOverlays.getDomNode());
+ this.viewParts.push(margin);
// Content widgets
this.contentWidgets = new ViewContentWidgets(this._context, this.domNode);
@@ -271,8 +278,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp
this.linesContent.appendChild(this.viewLines.getDomNode());
this.linesContent.appendChild(this.contentWidgets.domNode);
this.linesContent.appendChild(this.viewCursors.getDomNode());
- this.overflowGuardContainer.appendChild(marginViewOverlays.getDomNode());
- this.overflowGuardContainer.appendChild(this.viewZones.marginDomNode);
+ this.overflowGuardContainer.appendChild(margin.domNode);
this.overflowGuardContainer.appendChild(this.linesContentContainer);
this.overflowGuardContainer.appendChild(scrollDecoration.getDomNode());
this.overflowGuardContainer.appendChild(this.overlayWidgets.domNode);
diff --git a/src/vs/editor/browser/view/viewOverlays.ts b/src/vs/editor/browser/view/viewOverlays.ts
index 2d7bb97988d71af1368c15feed767b23095e483c..5834fc592fd41615396d91877a7f924d4c149101 100644
--- a/src/vs/editor/browser/view/viewOverlays.ts
+++ b/src/vs/editor/browser/view/viewOverlays.ts
@@ -233,7 +233,7 @@ export class MarginViewOverlays extends ViewOverlays {
this._contentLeft = context.configuration.editor.layoutInfo.contentLeft;
this._canUseTranslate3d = context.configuration.editor.viewInfo.canUseTranslate3d;
- this.domNode.setClassName(editorBrowser.ClassNames.MARGIN_VIEW_OVERLAYS + ' monaco-editor-background');
+ this.domNode.setClassName(editorBrowser.ClassNames.MARGIN_VIEW_OVERLAYS);
this.domNode.setWidth(1);
Configuration.applyFontInfo(this.domNode, this._context.configuration.editor.fontInfo);
@@ -283,14 +283,6 @@ export class MarginViewOverlays extends ViewOverlays {
_viewOverlaysRender(ctx: IRestrictedRenderingContext): void {
super._viewOverlaysRender(ctx);
- if (this._canUseTranslate3d) {
- let transform = 'translate3d(0px, ' + ctx.linesViewportData.visibleRangesDeltaTop + 'px, 0px)';
- this.domNode.setTransform(transform);
- this.domNode.setTop(0);
- } else {
- this.domNode.setTransform('');
- this.domNode.setTop(ctx.linesViewportData.visibleRangesDeltaTop);
- }
let height = Math.min(this._layoutProvider.getTotalHeight(), 1000000);
this.domNode.setHeight(height);
this.domNode.setWidth(this._contentLeft);
diff --git a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css
index 3339c59acd3fb0592058f55cd6dd6829bf73261c..474a00605c1cfbed637efb8859f640af70ce2f3c 100644
--- a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css
+++ b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css
@@ -10,6 +10,7 @@
vertical-align: middle;
box-sizing: border-box;
cursor: default;
+ height: 100%;
}
.monaco-editor .relative-current-line-number {
diff --git a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts
index d3dfaae05f972b0c2fc2334a8f1770cf757ebbd0..f86cffc5ab7c2e6bbc76cae9f27340e9c7ada2af 100644
--- a/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts
+++ b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts
@@ -97,20 +97,15 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
// --- end event handlers
public prepareRender(ctx: IRenderingContext): void {
- if (!this.shouldRender()) {
- throw new Error('I did not ask to render!');
- }
-
if (!this._renderLineNumbers) {
this._renderResult = null;
return;
}
let lineHeightClassName = (platform.isLinux ? (this._lineHeight % 2 === 0 ? ' lh-even' : ' lh-odd') : '');
- let lineHeight = this._lineHeight.toString();
let visibleStartLineNumber = ctx.visibleRange.startLineNumber;
let visibleEndLineNumber = ctx.visibleRange.endLineNumber;
- let common = '
';
+ let common = '
';
let output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css
index c0a5f0d205aed172cc46eb4e71bc8bc17907dc3a..452d83eeb8b7a106584573b8e352fe4305e07aac 100644
--- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css
+++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css
@@ -14,4 +14,5 @@
*/
.monaco-editor .margin-view-overlays .cldr {
position: absolute;
+ height: 100%;
}
\ No newline at end of file
diff --git a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts
index 1308f188f6daaa82a5fcc61f51c442fbff14c5ef..3517c9f31b42f40ce38a0447fb82de886c237b3a 100644
--- a/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts
+++ b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts
@@ -14,7 +14,6 @@ import { IRenderingContext } from 'vs/editor/common/view/renderingContext';
export class LinesDecorationsOverlay extends DedupOverlay {
private _context: ViewContext;
- private _lineHeight: number;
private _decorationsLeft: number;
private _decorationsWidth: number;
@@ -23,7 +22,6 @@ export class LinesDecorationsOverlay extends DedupOverlay {
constructor(context: ViewContext) {
super();
this._context = context;
- this._lineHeight = this._context.configuration.editor.lineHeight;
this._decorationsLeft = 0;
this._decorationsWidth = 0;
this._renderResult = null;
@@ -63,9 +61,6 @@ export class LinesDecorationsOverlay extends DedupOverlay {
return false;
}
public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
- if (e.lineHeight) {
- this._lineHeight = this._context.configuration.editor.lineHeight;
- }
return true;
}
public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
@@ -95,18 +90,13 @@ export class LinesDecorationsOverlay extends DedupOverlay {
}
public prepareRender(ctx: IRenderingContext): void {
- if (!this.shouldRender()) {
- throw new Error('I did not ask to render!');
- }
-
let visibleStartLineNumber = ctx.visibleRange.startLineNumber;
let visibleEndLineNumber = ctx.visibleRange.endLineNumber;
let toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));
- let lineHeight = this._lineHeight.toString();
let left = this._decorationsLeft.toString();
let width = this._decorationsWidth.toString();
- let common = '" style="left:' + left + 'px;width:' + width + 'px' + ';height:' + lineHeight + 'px;">
';
+ let common = '" style="left:' + left + 'px;width:' + width + 'px;">
';
let output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
@@ -126,10 +116,6 @@ export class LinesDecorationsOverlay extends DedupOverlay {
if (!this._renderResult) {
return '';
}
- let lineIndex = lineNumber - startLineNumber;
- if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
- throw new Error('Unexpected render request');
- }
- return this._renderResult[lineIndex];
+ return this._renderResult[lineNumber - startLineNumber];
}
}
\ No newline at end of file
diff --git a/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts
new file mode 100644
index 0000000000000000000000000000000000000000..77a0f5c9b2c912d308aea6d6dd1aa712fc4decdc
--- /dev/null
+++ b/src/vs/editor/browser/viewParts/margin/margin.ts
@@ -0,0 +1,83 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+'use strict';
+
+import { StyleMutator } from 'vs/base/browser/styleMutator';
+import * as editorCommon from 'vs/editor/common/editorCommon';
+import { ViewPart } from 'vs/editor/browser/view/viewPart';
+import { ViewContext } from 'vs/editor/common/view/viewContext';
+import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
+import { ILayoutProvider } from 'vs/editor/browser/viewLayout/layoutProvider';
+
+export class Margin extends ViewPart {
+ public domNode: HTMLElement;
+ private _layoutProvider: ILayoutProvider;
+ private _canUseTranslate3d: boolean;
+ private _height: number;
+ private _contentLeft: number;
+
+ constructor(context: ViewContext, layoutProvider: ILayoutProvider) {
+ super(context);
+ this._layoutProvider = layoutProvider;
+ this._canUseTranslate3d = this._context.configuration.editor.viewInfo.canUseTranslate3d;
+ this.domNode = this._createDomNode();
+ this._height = this._context.configuration.editor.layoutInfo.contentHeight;
+ this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
+ }
+
+ public dispose(): void {
+ super.dispose();
+ }
+
+ public _createDomNode(): HTMLElement {
+ let domNode = document.createElement('div');
+ domNode.className = 'margin monaco-editor-background';
+ domNode.style.position = 'absolute';
+ domNode.setAttribute('role', 'presentation');
+ domNode.setAttribute('aria-hidden', 'true');
+ return domNode;
+ }
+
+ // --- begin event handlers
+
+ public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
+ if (e.viewInfo.canUseTranslate3d) {
+ this._canUseTranslate3d = this._context.configuration.editor.viewInfo.canUseTranslate3d;
+ }
+
+ return super.onConfigurationChanged(e);
+ }
+
+ public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
+ return super.onScrollChanged(e) || e.scrollTopChanged;
+ }
+
+ public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
+ this._contentLeft = layoutInfo.contentLeft;
+ return super.onLayoutChanged(layoutInfo) || true;
+ }
+
+ // --- end event handlers
+
+ public prepareRender(ctx: IRenderingContext): void {
+ // Nothing to read
+ }
+
+ public render(ctx: IRestrictedRenderingContext): void {
+ if (this._canUseTranslate3d) {
+ let transform = 'translate3d(0px, ' + ctx.linesViewportData.visibleRangesDeltaTop + 'px, 0px)';
+ StyleMutator.setTransform(this.domNode, transform);
+ StyleMutator.setTop(this.domNode, 0);
+ } else {
+ StyleMutator.setTransform(this.domNode, '');
+ StyleMutator.setTop(this.domNode, ctx.linesViewportData.visibleRangesDeltaTop);
+ }
+
+ let height = Math.min(this._layoutProvider.getTotalHeight(), 1000000);
+ StyleMutator.setHeight(this.domNode, height);
+ StyleMutator.setWidth(this.domNode, this._contentLeft);
+ }
+}
diff --git a/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css
new file mode 100644
index 0000000000000000000000000000000000000000..7bd8f89ab0ea7616a1368bef8d56a274ea923ad4
--- /dev/null
+++ b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css
@@ -0,0 +1,15 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+/*
+ Keeping name short for faster parsing.
+ cmdr = core margin decorations rendering (div)
+*/
+.monaco-editor .margin-view-overlays .cmdr {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
\ No newline at end of file
diff --git a/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6ea01669a601be048348c7d12a650687b1c3d760
--- /dev/null
+++ b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts
@@ -0,0 +1,109 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+'use strict';
+
+import 'vs/css!./marginDecorations';
+import * as editorCommon from 'vs/editor/common/editorCommon';
+import { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';
+import { ViewContext } from 'vs/editor/common/view/viewContext';
+import { IRenderingContext } from 'vs/editor/common/view/renderingContext';
+
+export class MarginViewLineDecorationsOverlay extends DedupOverlay {
+ private _context: ViewContext;
+ private _renderResult: string[];
+
+ constructor(context: ViewContext) {
+ super();
+ this._context = context;
+ this._renderResult = null;
+ this._context.addEventHandler(this);
+ }
+
+ public dispose(): void {
+ this._context.removeEventHandler(this);
+ this._context = null;
+ this._renderResult = null;
+ }
+
+ // --- begin event handlers
+
+ public onModelFlushed(): boolean {
+ return true;
+ }
+ public onModelDecorationsChanged(e: editorCommon.IViewDecorationsChangedEvent): boolean {
+ return true;
+ }
+ public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): boolean {
+ return true;
+ }
+ public onModelLineChanged(e: editorCommon.IViewLineChangedEvent): boolean {
+ return true;
+ }
+ public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): boolean {
+ return true;
+ }
+ public onCursorPositionChanged(e: editorCommon.IViewCursorPositionChangedEvent): boolean {
+ return false;
+ }
+ public onCursorSelectionChanged(e: editorCommon.IViewCursorSelectionChangedEvent): boolean {
+ return false;
+ }
+ public onCursorRevealRange(e: editorCommon.IViewRevealRangeEvent): boolean {
+ return false;
+ }
+ public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
+ return true;
+ }
+ public onLayoutChanged(layoutInfo: editorCommon.EditorLayoutInfo): boolean {
+ return true;
+ }
+ public onScrollChanged(e: editorCommon.IScrollEvent): boolean {
+ return e.scrollTopChanged;
+ }
+ public onZonesChanged(): boolean {
+ return true;
+ }
+
+ // --- end event handlers
+
+ protected _getDecorations(ctx: IRenderingContext): DecorationToRender[] {
+ let decorations = ctx.getDecorationsInViewport();
+ let r: DecorationToRender[] = [];
+ for (let i = 0, len = decorations.length; i < len; i++) {
+ let d = decorations[i];
+ if (d.options.marginClassName) {
+ r.push(new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, d.options.marginClassName));
+ }
+ }
+ return r;
+ }
+
+ public prepareRender(ctx: IRenderingContext): void {
+ let visibleStartLineNumber = ctx.visibleRange.startLineNumber;
+ let visibleEndLineNumber = ctx.visibleRange.endLineNumber;
+ let toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));
+
+ let output: string[] = [];
+ for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
+ let lineIndex = lineNumber - visibleStartLineNumber;
+ let classNames = toRender[lineIndex];
+ let lineOutput = '';
+ for (let i = 0, len = classNames.length; i < len; i++) {
+ lineOutput += '';
+ }
+ output[lineIndex] = lineOutput;
+ }
+
+ this._renderResult = output;
+ }
+
+ public render(startLineNumber: number, lineNumber: number): string {
+ if (!this._renderResult) {
+ return '';
+ }
+ return this._renderResult[lineNumber - startLineNumber];
+ }
+}
\ No newline at end of file
diff --git a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts
index d79a83ccc488cf51e3fcc5b71c76bb28c6e94f1a..1fb668ff8915036c02f141a13b07b0107d7dfc84 100644
--- a/src/vs/editor/browser/viewParts/viewZones/viewZones.ts
+++ b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts
@@ -344,7 +344,7 @@ export class ViewZones extends ViewPart {
StyleMutator.setDisplay(zone.delegate.domNode, newDisplay);
if (zone.delegate.marginDomNode) {
- StyleMutator.setTop(zone.delegate.marginDomNode, newTop - ctx.viewportTop);
+ StyleMutator.setTop(zone.delegate.marginDomNode, newTop);
StyleMutator.setHeight(zone.delegate.marginDomNode, newHeight);
StyleMutator.setDisplay(zone.delegate.marginDomNode, newDisplay);
}
diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts
index 1b041b7332192640ed877b78f6a3bf5c3418c76d..483fe54e7e5da82ae0796db98534af22baf58c54 100644
--- a/src/vs/editor/common/editorCommon.ts
+++ b/src/vs/editor/common/editorCommon.ts
@@ -1150,6 +1150,10 @@ export interface IModelDecorationOptions {
* If set, the decoration will be rendered in the lines decorations with this CSS class name.
*/
linesDecorationsClassName?: string;
+ /**
+ * If set, the decoration will be rendered in the margin (covering its full width) with this CSS class name.
+ */
+ marginClassName?: string;
/**
* If set, the decoration will be rendered inline with the text with this CSS class name.
* Please use this only for CSS rules that must impact the text. For example, use `className`
diff --git a/src/vs/editor/common/model/textModelWithDecorations.ts b/src/vs/editor/common/model/textModelWithDecorations.ts
index fc5515fa54d11e8e8b90d9b7fc5405bb35533ed6..f42af47cf09ada0adb4f42cede0af4f671b6458e 100644
--- a/src/vs/editor/common/model/textModelWithDecorations.ts
+++ b/src/vs/editor/common/model/textModelWithDecorations.ts
@@ -654,6 +654,7 @@ class ModelDecorationOptions implements editorCommon.IModelDecorationOptions {
overviewRuler: editorCommon.IModelDecorationOverviewRulerOptions;
glyphMarginClassName: string;
linesDecorationsClassName: string;
+ marginClassName: string;
inlineClassName: string;
beforeContentClassName: string;
afterContentClassName: string;
@@ -667,6 +668,7 @@ class ModelDecorationOptions implements editorCommon.IModelDecorationOptions {
this.overviewRuler = _normalizeOverviewRulerOptions(options.overviewRuler, options.showInOverviewRuler);
this.glyphMarginClassName = cleanClassName(options.glyphMarginClassName || strings.empty);
this.linesDecorationsClassName = cleanClassName(options.linesDecorationsClassName || strings.empty);
+ this.marginClassName = cleanClassName(options.marginClassName || strings.empty);
this.inlineClassName = cleanClassName(options.inlineClassName || strings.empty);
this.beforeContentClassName = cleanClassName(options.beforeContentClassName || strings.empty);
this.afterContentClassName = cleanClassName(options.afterContentClassName || strings.empty);
@@ -689,6 +691,7 @@ class ModelDecorationOptions implements editorCommon.IModelDecorationOptions {
&& this.showInOverviewRuler === other.showInOverviewRuler
&& this.glyphMarginClassName === other.glyphMarginClassName
&& this.linesDecorationsClassName === other.linesDecorationsClassName
+ && this.marginClassName === other.marginClassName
&& this.inlineClassName === other.inlineClassName
&& this.beforeContentClassName === other.beforeContentClassName
&& this.afterContentClassName === other.afterContentClassName
diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts
index aa95e16b7d69abe2327f7b73d29d7a350aeb807e..1ed20aabbfa43fb09ac3bcdb5ff41a5955ffc0f7 100644
--- a/src/vs/monaco.d.ts
+++ b/src/vs/monaco.d.ts
@@ -1581,6 +1581,10 @@ declare module monaco.editor {
* If set, the decoration will be rendered in the lines decorations with this CSS class name.
*/
linesDecorationsClassName?: string;
+ /**
+ * If set, the decoration will be rendered in the margin (covering its full width) with this CSS class name.
+ */
+ marginClassName?: string;
/**
* If set, the decoration will be rendered inline with the text with this CSS class name.
* Please use this only for CSS rules that must impact the text. For example, use `className`