Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -25,6 +25,13 @@ export interface IViewZoneData {
afterLineNumber: number;
}
export interface IMarginData {
isAfterLines: boolean;
glyphMarginWidth: number;
lineNumbersWidth: number;
offsetX: number;
}
interface IETextRange {
boundingHeight: number;
boundingLeft: number;
@@ -565,22 +572,28 @@ export class MouseTargetFactory {
if (request.isInMarginArea) {
let res = ctx.getFullLineRangeAtCoord(request.mouseVerticalOffset);
let pos = res.range.getStartPosition();
let offset = Math.abs(request.pos.x - request.editorPos.x);
const detail: IMarginData = {
isAfterLines: res.isAfterLines,
glyphMarginWidth: ctx.layoutInfo.glyphMarginWidth,
lineNumbersWidth: ctx.layoutInfo.lineNumbersWidth,
offsetX: offset
};
if (offset <= ctx.layoutInfo.glyphMarginWidth) {
// On the glyph margin
return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, res.isAfterLines);
return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail);
}
offset -= ctx.layoutInfo.glyphMarginWidth;
if (offset <= ctx.layoutInfo.lineNumbersWidth) {
// On the line numbers
return request.fulfill(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, res.isAfterLines);
return request.fulfill(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, detail);
}
offset -= ctx.layoutInfo.lineNumbersWidth;
// On the line decorations
return request.fulfill(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, res.isAfterLines);
return request.fulfill(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, detail);
}
return null;
}

View File

@@ -7,6 +7,7 @@
import 'vs/css!./textAreaHandler';
import * as platform from 'vs/base/common/platform';
import * as browser from 'vs/base/browser/browser';
import * as strings from 'vs/base/common/strings';
import { TextAreaInput, ITextAreaInputHost, IPasteData, ICompositionData } from 'vs/editor/browser/controller/textAreaInput';
import { ISimpleModel, ITypeData, TextAreaState, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState';
import { Range } from 'vs/editor/common/core/range';
@@ -164,10 +165,24 @@ export class TextAreaHandler extends ViewPart {
if (this._accessibilitySupport === platform.AccessibilitySupport.Disabled) {
// We know for a fact that a screen reader is not attached
// On OSX, we write the character before the cursor to allow for "long-press" composition
if (platform.isMacintosh) {
const selection = this._selections[0];
if (selection.isEmpty()) {
const position = selection.getStartPosition();
if (position.column > 1) {
const lineContent = this._context.model.getLineContent(position.lineNumber);
const charBefore = lineContent.charAt(position.column - 2);
if (!strings.isHighSurrogate(charBefore.charCodeAt(0))) {
return new TextAreaState(charBefore, 1, 1, position, position);
}
}
}
}
return TextAreaState.EMPTY;
}
return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0]);
return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0], this._accessibilitySupport === platform.AccessibilitySupport.Unknown);
},
deduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => {

View File

@@ -111,7 +111,7 @@ export class TextAreaInput extends Disposable {
this._nextCommand = ReadFromTextArea.Type;
this._register(dom.addStandardDisposableListener(textArea.domNode, 'keydown', (e: IKeyboardEvent) => {
if (this._isDoingComposition && e.equals(KeyCode.KEY_IN_COMPOSITION)) {
if (this._isDoingComposition && e.keyCode === KeyCode.KEY_IN_COMPOSITION) {
// Stop propagation for keyDown events if the IME is processing key input
e.stopPropagation();
}

View File

@@ -241,7 +241,7 @@ export class PagedScreenReaderStrategy {
return new Range(startLineNumber, 1, endLineNumber + 1, 1);
}
public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range): TextAreaState {
public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range, trimLongText: boolean): TextAreaState {
let selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber);
let selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage);
@@ -273,15 +273,17 @@ export class PagedScreenReaderStrategy {
// Chromium handles very poorly text even of a few thousand chars
// Cut text to avoid stalling the entire UI
const LIMIT_CHARS = 500;
if (pretext.length > LIMIT_CHARS) {
pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length);
}
if (posttext.length > LIMIT_CHARS) {
posttext = posttext.substring(0, LIMIT_CHARS);
}
if (text.length > 2 * LIMIT_CHARS) {
text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length);
if (trimLongText) {
const LIMIT_CHARS = 500;
if (pretext.length > LIMIT_CHARS) {
pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length);
}
if (posttext.length > LIMIT_CHARS) {
posttext = posttext.substring(0, LIMIT_CHARS);
}
if (text.length > 2 * LIMIT_CHARS) {
text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length);
}
}
return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, new Position(selection.startLineNumber, selection.startColumn), new Position(selection.endLineNumber, selection.endColumn));

View File

@@ -308,7 +308,8 @@ export class View extends ViewEventHandler {
}
private getEditorClassName() {
return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type);
let focused = this._textAreaHandler.isFocused() ? ' focused' : '';
return this._context.configuration.editor.editorClassName + ' ' + getThemeTypeSelector(this._context.theme.type) + focused;
}
// --- begin event handlers
@@ -323,7 +324,7 @@ export class View extends ViewEventHandler {
return false;
}
public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {
this.domNode.toggleClassName('focused', e.isFocused);
this.domNode.setClassName(this.getEditorClassName());
if (e.isFocused) {
this.outgoingEvents.emitViewFocusGained();
} else {
@@ -419,6 +420,11 @@ export class View extends ViewEventHandler {
this._context.model
);
if (this.contentWidgets.shouldRender()) {
// Give the content widgets a chance to set their max width before a possible synchronous layout
this.contentWidgets.onBeforeRender(viewportData);
}
if (this.viewLines.shouldRender()) {
this.viewLines.renderText(viewportData);
this.viewLines.onDidRender();

View File

@@ -13,6 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
import { Position, IPosition } from 'vs/editor/common/core/position';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
class Coordinate {
_coordinateBrand: void;
@@ -73,6 +74,14 @@ export class ViewContentWidgets extends ViewPart {
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
return true;
}
public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {
let keys = Object.keys(this._widgets);
for (let i = 0, len = keys.length; i < len; i++) {
const widgetId = keys[i];
this._widgets[widgetId].onLineMappingChanged(e);
}
return true;
}
public onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {
return true;
}
@@ -132,6 +141,14 @@ export class ViewContentWidgets extends ViewPart {
return false;
}
public onBeforeRender(viewportData: ViewportData): void {
let keys = Object.keys(this._widgets);
for (let i = 0, len = keys.length; i < len; i++) {
const widgetId = keys[i];
this._widgets[widgetId].onBeforeRender(viewportData);
}
}
public prepareRender(ctx: RenderingContext): void {
let keys = Object.keys(this._widgets);
for (let i = 0, len = keys.length; i < len; i++) {
@@ -173,8 +190,13 @@ class Widget {
private _lineHeight: number;
private _position: IPosition;
private _viewPosition: Position;
private _preference: ContentWidgetPositionPreference[];
private _cachedDomNodeClientWidth: number;
private _cachedDomNodeClientHeight: number;
private _maxWidth: number;
private _isVisible: boolean;
private _renderData: Coordinate;
constructor(context: ViewContext, viewDomNode: FastDomNode<HTMLElement>, actual: IContentWidget) {
@@ -192,15 +214,18 @@ class Widget {
this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
this._lineHeight = this._context.configuration.editor.lineHeight;
this._position = null;
this._setPosition(null);
this._preference = null;
this._cachedDomNodeClientWidth = -1;
this._cachedDomNodeClientHeight = -1;
this._maxWidth = this._getMaxWidth();
this._isVisible = false;
this._renderData = null;
this.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute');
this._updateMaxWidth();
this.domNode.setVisibility('hidden');
this.domNode.setAttribute('widgetId', this.id);
this.domNode.setMaxWidth(this._maxWidth);
}
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void {
@@ -210,22 +235,40 @@ class Widget {
if (e.layoutInfo) {
this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth;
this._updateMaxWidth();
this._maxWidth = this._getMaxWidth();
}
}
private _updateMaxWidth(): void {
const maxWidth = this.allowEditorOverflow
? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
: this._contentWidth;
public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): void {
this._setPosition(this._position);
}
this.domNode.setMaxWidth(maxWidth);
private _setPosition(position: IPosition): void {
this._position = position;
this._viewPosition = null;
if (this._position) {
// Do not trust that widgets give a valid position
const validModelPosition = this._context.model.validateModelPosition(this._position);
if (this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) {
this._viewPosition = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition);
}
}
}
private _getMaxWidth(): number {
return (
this.allowEditorOverflow
? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
: this._contentWidth
);
}
public setPosition(position: IPosition, preference: ContentWidgetPositionPreference[]): void {
this._position = position;
this._setPosition(position);
this._preference = preference;
this._cachedDomNodeClientWidth = -1;
this._cachedDomNodeClientHeight = -1;
}
private _layoutBoxInViewport(topLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult {
@@ -312,50 +355,44 @@ class Widget {
return new Coordinate(topLeft.top, topLeft.left + this._contentLeft);
}
private _getTopLeft(ctx: RenderingContext, position: Position): Coordinate {
const visibleRange = ctx.visibleRangeForPosition(position);
/**
* Compute `this._topLeft`
*/
private _getTopLeft(ctx: RenderingContext): Coordinate {
if (!this._viewPosition) {
return null;
}
const visibleRange = ctx.visibleRangeForPosition(this._viewPosition);
if (!visibleRange) {
return null;
}
const top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.scrollTop;
const top = ctx.getVerticalOffsetForLineNumber(this._viewPosition.lineNumber) - ctx.scrollTop;
return new Coordinate(top, visibleRange.left);
}
private _prepareRenderWidget(ctx: RenderingContext): Coordinate {
if (!this._position || !this._preference) {
private _prepareRenderWidget(topLeft: Coordinate, ctx: RenderingContext): Coordinate {
if (!topLeft) {
return null;
}
// Do not trust that widgets have a valid position
let validModelPosition = this._context.model.validateModelPosition(this._position);
if (!this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) {
// this position is hidden by the view model
return null;
}
let position = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition);
let placement: IBoxLayoutResult = null;
let fetchPlacement = (): void => {
if (placement) {
return;
}
const topLeft = this._getTopLeft(ctx, position);
if (!topLeft) {
return;
if (this._cachedDomNodeClientWidth === -1 || this._cachedDomNodeClientHeight === -1) {
const domNode = this.domNode.domNode;
this._cachedDomNodeClientWidth = domNode.clientWidth;
this._cachedDomNodeClientHeight = domNode.clientHeight;
}
const domNode = this.domNode.domNode;
const width = domNode.clientWidth;
const height = domNode.clientHeight;
if (this.allowEditorOverflow) {
placement = this._layoutBoxInPage(topLeft, width, height, ctx);
placement = this._layoutBoxInPage(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx);
} else {
placement = this._layoutBoxInViewport(topLeft, width, height, ctx);
placement = this._layoutBoxInViewport(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx);
}
};
@@ -382,11 +419,6 @@ class Widget {
return new Coordinate(placement.belowTop, placement.left);
}
} else {
const topLeft = this._getTopLeft(ctx, position);
if (!topLeft) {
// Widget outside of viewport
return null;
}
if (this.allowEditorOverflow) {
return this._prepareRenderWidgetAtExactPositionOverflowing(topLeft);
} else {
@@ -398,8 +430,25 @@ class Widget {
return null;
}
/**
* 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._viewPosition || !this._preference) {
return;
}
if (this._viewPosition.lineNumber < viewportData.startLineNumber || this._viewPosition.lineNumber > viewportData.endLineNumber) {
// Outside of viewport
return;
}
this.domNode.setMaxWidth(this._maxWidth);
}
public prepareRender(ctx: RenderingContext): void {
this._renderData = this._prepareRenderWidget(ctx);
const topLeft = this._getTopLeft(ctx);
this._renderData = this._prepareRenderWidget(topLeft, ctx);
}
public render(ctx: RestrictedRenderingContext): void {

View File

@@ -110,8 +110,12 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
public render(startLineNumber: number, lineNumber: number): string {
if (lineNumber === this._primaryCursorLineNumber) {
if (this._shouldShowCurrentLine()) {
const paintedInMargin = this._willRenderMarginCurrentLine();
const className = 'current-line' + (paintedInMargin ? ' current-line-both' : '');
return (
'<div class="current-line" style="width:'
'<div class="'
+ className
+ '" style="width:'
+ String(Math.max(this._scrollWidth, this._contentWidth))
+ 'px; height:'
+ String(this._lineHeight)
@@ -125,9 +129,18 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
}
private _shouldShowCurrentLine(): boolean {
return (this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all') &&
this._selectionIsEmpty &&
this._primaryCursorIsInEditableRange;
return (
(this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all')
&& this._selectionIsEmpty
&& this._primaryCursorIsInEditableRange
);
}
private _willRenderMarginCurrentLine(): boolean {
return (
(this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all')
&& this._primaryCursorIsInEditableRange
);
}
}

View File

@@ -9,4 +9,8 @@
left: 0;
top: 0;
box-sizing: border-box;
}
.monaco-editor .margin-view-overlays .current-line-margin.current-line-margin-both {
border-right: 0;
}

View File

@@ -17,6 +17,7 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
private _context: ViewContext;
private _lineHeight: number;
private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all';
private _selectionIsEmpty: boolean;
private _primaryCursorIsInEditableRange: boolean;
private _primaryCursorLineNumber: number;
private _contentLeft: number;
@@ -27,6 +28,7 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
this._lineHeight = this._context.configuration.editor.lineHeight;
this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight;
this._selectionIsEmpty = true;
this._primaryCursorIsInEditableRange = true;
this._primaryCursorLineNumber = 1;
this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft;
@@ -68,6 +70,13 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
hasChanged = true;
}
const selectionIsEmpty = e.selections[0].isEmpty();
if (this._selectionIsEmpty !== selectionIsEmpty) {
this._selectionIsEmpty = selectionIsEmpty;
hasChanged = true;
return true;
}
return hasChanged;
}
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
@@ -90,8 +99,12 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
public render(startLineNumber: number, lineNumber: number): string {
if (lineNumber === this._primaryCursorLineNumber) {
if (this._shouldShowCurrentLine()) {
const paintedInContent = this._willRenderContentCurrentLine();
const className = 'current-line-margin' + (paintedInContent ? ' current-line-margin-both' : '');
return (
'<div class="current-line-margin" style="width:'
'<div class="'
+ className
+ '" style="width:'
+ String(this._contentLeft)
+ 'px; height:'
+ String(this._lineHeight)
@@ -105,7 +118,18 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
}
private _shouldShowCurrentLine(): boolean {
return (this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all') && this._primaryCursorIsInEditableRange;
return (
(this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all')
&& this._primaryCursorIsInEditableRange
);
}
private _willRenderContentCurrentLine(): boolean {
return (
(this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all')
&& this._selectionIsEmpty
&& this._primaryCursorIsInEditableRange
);
}
}

View File

@@ -78,15 +78,15 @@ export class DecorationsOverlay extends DynamicViewOverlay {
let decorations: ViewModelDecoration[] = [], decorationsLen = 0;
for (let i = 0, len = _decorations.length; i < len; i++) {
let d = _decorations[i];
if (d.source.options.className) {
if (d.options.className) {
decorations[decorationsLen++] = d;
}
}
// Sort decorations for consistent render output
decorations = decorations.sort((a, b) => {
let aClassName = a.source.options.className;
let bClassName = b.source.options.className;
let aClassName = a.options.className;
let bClassName = b.options.className;
if (aClassName < bClassName) {
return -1;
@@ -120,13 +120,13 @@ export class DecorationsOverlay extends DynamicViewOverlay {
for (let i = 0, lenI = decorations.length; i < lenI; i++) {
let d = decorations[i];
if (!d.source.options.isWholeLine) {
if (!d.options.isWholeLine) {
continue;
}
let decorationOutput = (
'<div class="cdr '
+ d.source.options.className
+ d.options.className
+ '" style="left:0;width:100%;height:'
+ lineHeight
+ 'px;"></div>'
@@ -148,12 +148,12 @@ export class DecorationsOverlay extends DynamicViewOverlay {
for (let i = 0, lenI = decorations.length; i < lenI; i++) {
const d = decorations[i];
if (d.source.options.isWholeLine) {
if (d.options.isWholeLine) {
continue;
}
const className = d.source.options.className;
const showIfCollapsed = d.source.options.showIfCollapsed;
const className = d.options.className;
const showIfCollapsed = d.options.showIfCollapsed;
let range = d.range;
if (showIfCollapsed && range.endColumn === 1 && range.endLineNumber !== range.startLineNumber) {

View File

@@ -145,7 +145,7 @@ export class GlyphMarginOverlay extends DedupOverlay {
let r: DecorationToRender[] = [], rLen = 0;
for (let i = 0, len = decorations.length; i < len; i++) {
let d = decorations[i];
let glyphMarginClassName = d.source.options.glyphMarginClassName;
let glyphMarginClassName = d.options.glyphMarginClassName;
if (glyphMarginClassName) {
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName);
}

View File

@@ -77,6 +77,9 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {
return true;
}
public onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean {
return true;
}
// --- end event handlers
@@ -93,10 +96,12 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
const lineHeight = this._lineHeight;
const indentGuideWidth = dom.computeScreenAwareSize(1);
const indents = this._context.model.getLinesIndentGuides(visibleStartLineNumber, visibleEndLineNumber);
let output: string[] = [];
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
let lineIndex = lineNumber - visibleStartLineNumber;
let indent = this._context.model.getLineIndentGuide(lineNumber);
const lineIndex = lineNumber - visibleStartLineNumber;
const indent = indents[lineIndex];
let result = '';
let leftMostVisiblePosition = ctx.visibleRangeForPosition(new Position(lineNumber, 1));

View File

@@ -397,7 +397,7 @@ class RenderedViewLine implements IRenderedViewLine {
this._pixelOffsetCache = null;
if (!containsRTL || this._characterMapping.length === 0 /* the line is empty */) {
this._pixelOffsetCache = new Int32Array(this._characterMapping.length + 1);
this._pixelOffsetCache = new Int32Array(Math.max(2, this._characterMapping.length + 1));
for (let column = 0, len = this._characterMapping.length; column <= len; column++) {
this._pixelOffsetCache[column] = -1;
}

View File

@@ -551,17 +551,17 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
}
}
// (3) handle scrolling
this._linesContent.setLayerHinting(this._canUseLayerHinting);
const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta;
this._linesContent.setTop(-adjustedScrollTop);
this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft());
// Update max line width (not so important, it is just so the horizontal scrollbar doesn't get too small)
if (!this._updateLineWidthsFast()) {
// Computing the width of some lines would be slow => delay it
this._asyncUpdateLineWidths.schedule();
}
// (3) handle scrolling
this._linesContent.setLayerHinting(this._canUseLayerHinting);
const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta;
this._linesContent.setTop(-adjustedScrollTop);
this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft());
}
// --- width

View File

@@ -73,7 +73,7 @@ export class LinesDecorationsOverlay extends DedupOverlay {
let r: DecorationToRender[] = [], rLen = 0;
for (let i = 0, len = decorations.length; i < len; i++) {
let d = decorations[i];
let linesDecorationsClassName = d.source.options.linesDecorationsClassName;
let linesDecorationsClassName = d.options.linesDecorationsClassName;
if (linesDecorationsClassName) {
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, linesDecorationsClassName);
}

View File

@@ -63,7 +63,7 @@ export class MarginViewLineDecorationsOverlay extends DedupOverlay {
let r: DecorationToRender[] = [], rLen = 0;
for (let i = 0, len = decorations.length; i < len; i++) {
let d = decorations[i];
let marginClassName = d.source.options.marginClassName;
let marginClassName = d.options.marginClassName;
if (marginClassName) {
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, marginClassName);
}

View File

@@ -709,7 +709,7 @@ export class Minimap extends ViewPart {
const imageData = this._getBuffer();
// Render untouched lines by using last rendered data.
let needed = Minimap._renderUntouchedLines(
let [_dirtyY1, _dirtyY2, needed] = Minimap._renderUntouchedLines(
imageData,
startLineNumber,
endLineNumber,
@@ -744,9 +744,13 @@ export class Minimap extends ViewPart {
dy += minimapLineHeight;
}
const dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1);
const dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2);
const dirtyHeight = dirtyY2 - dirtyY1;
// Finally, paint to the canvas
const ctx = this._canvas.domNode.getContext('2d');
ctx.putImageData(imageData, 0, 0);
ctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight);
// Save rendered data for reuse on next frame if possible
return new RenderData(
@@ -762,14 +766,14 @@ export class Minimap extends ViewPart {
endLineNumber: number,
minimapLineHeight: number,
lastRenderData: RenderData,
): boolean[] {
): [number, number, boolean[]] {
let needed: boolean[] = [];
if (!lastRenderData) {
for (let i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) {
needed[i] = true;
}
return needed;
return [-1, -1, needed];
}
const _lastData = lastRenderData._get();
@@ -780,6 +784,10 @@ export class Minimap extends ViewPart {
const WIDTH = target.width;
const targetData = target.data;
const maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4;
let dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame
let dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame
let copySourceStart = -1;
let copySourceEnd = -1;
let copyDestStart = -1;
@@ -810,6 +818,12 @@ export class Minimap extends ViewPart {
if (copySourceStart !== -1) {
// flush existing copy request
targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);
if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {
dirtyPixel1 = copySourceEnd;
}
if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {
dirtyPixel2 = copySourceStart;
}
}
copySourceStart = sourceStart;
copySourceEnd = sourceEnd;
@@ -824,9 +838,18 @@ export class Minimap extends ViewPart {
if (copySourceStart !== -1) {
// flush existing copy request
targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);
if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {
dirtyPixel1 = copySourceEnd;
}
if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {
dirtyPixel2 = copySourceStart;
}
}
return needed;
const dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4));
const dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4));
return [dirtyY1, dirtyY2, needed];
}
private static _renderLine(

View File

@@ -6,262 +6,416 @@
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { OverviewRulerImpl } from 'vs/editor/browser/viewParts/overviewRuler/overviewRulerImpl';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
import { Position } from 'vs/editor/common/core/position';
import { TokenizationRegistry } from 'vs/editor/common/modes';
import { IDisposable } from 'vs/base/common/lifecycle';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
import { editorOverviewRulerBorder, editorCursorForeground } from 'vs/editor/common/view/editorColorRegistry';
import { Color } from 'vs/base/common/color';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { ITheme } from 'vs/platform/theme/common/themeService';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
class Settings {
public readonly lineHeight: number;
public readonly pixelRatio: number;
public readonly overviewRulerLanes: number;
public readonly renderBorder: boolean;
public readonly borderColor: string;
public readonly hideCursor: boolean;
public readonly cursorColor: string;
public readonly themeType: 'light' | 'dark' | 'hc';
public readonly backgroundColor: string;
public readonly top: number;
public readonly right: number;
public readonly domWidth: number;
public readonly domHeight: number;
public readonly canvasWidth: number;
public readonly canvasHeight: number;
public readonly x: number[];
public readonly w: number[];
constructor(config: editorCommon.IConfiguration, theme: ITheme) {
this.lineHeight = config.editor.lineHeight;
this.pixelRatio = config.editor.pixelRatio;
this.overviewRulerLanes = config.editor.viewInfo.overviewRulerLanes;
this.renderBorder = config.editor.viewInfo.overviewRulerBorder;
const borderColor = theme.getColor(editorOverviewRulerBorder);
this.borderColor = borderColor ? borderColor.toString() : null;
this.hideCursor = config.editor.viewInfo.hideCursorInOverviewRuler;
const cursorColor = theme.getColor(editorCursorForeground);
this.cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null;
this.themeType = theme.type;
const minimapEnabled = config.editor.viewInfo.minimap.enabled;
const backgroundColor = (minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null);
this.backgroundColor = (backgroundColor ? Color.Format.CSS.formatHex(backgroundColor) : null);
const position = config.editor.layoutInfo.overviewRuler;
this.top = position.top;
this.right = position.right;
this.domWidth = position.width;
this.domHeight = position.height;
this.canvasWidth = (this.domWidth * this.pixelRatio) | 0;
this.canvasHeight = (this.domHeight * this.pixelRatio) | 0;
const [x, w] = this._initLanes(1, this.canvasWidth, this.overviewRulerLanes);
this.x = x;
this.w = w;
}
private _initLanes(canvasLeftOffset: number, canvasWidth: number, laneCount: number): [number[], number[]] {
const remainingWidth = canvasWidth - canvasLeftOffset;
if (laneCount >= 3) {
const leftWidth = Math.floor(remainingWidth / 3);
const rightWidth = Math.floor(remainingWidth / 3);
const centerWidth = remainingWidth - leftWidth - rightWidth;
const leftOffset = canvasLeftOffset;
const centerOffset = leftOffset + leftWidth;
const rightOffset = leftOffset + leftWidth + centerWidth;
return [
[
0,
leftOffset, // Left
centerOffset, // Center
leftOffset, // Left | Center
rightOffset, // Right
leftOffset, // Left | Right
centerOffset, // Center | Right
leftOffset, // Left | Center | Right
], [
0,
leftWidth, // Left
centerWidth, // Center
leftWidth + centerWidth, // Left | Center
rightWidth, // Right
leftWidth + centerWidth + rightWidth, // Left | Right
centerWidth + rightWidth, // Center | Right
leftWidth + centerWidth + rightWidth, // Left | Center | Right
]
];
} else if (laneCount === 2) {
const leftWidth = Math.floor(remainingWidth / 2);
const rightWidth = remainingWidth - leftWidth;
const leftOffset = canvasLeftOffset;
const rightOffset = leftOffset + leftWidth;
return [
[
0,
leftOffset, // Left
leftOffset, // Center
leftOffset, // Left | Center
rightOffset, // Right
leftOffset, // Left | Right
leftOffset, // Center | Right
leftOffset, // Left | Center | Right
], [
0,
leftWidth, // Left
leftWidth, // Center
leftWidth, // Left | Center
rightWidth, // Right
leftWidth + rightWidth, // Left | Right
leftWidth + rightWidth, // Center | Right
leftWidth + rightWidth, // Left | Center | Right
]
];
} else {
const offset = canvasLeftOffset;
const width = remainingWidth;
return [
[
0,
offset, // Left
offset, // Center
offset, // Left | Center
offset, // Right
offset, // Left | Right
offset, // Center | Right
offset, // Left | Center | Right
], [
0,
width, // Left
width, // Center
width, // Left | Center
width, // Right
width, // Left | Right
width, // Center | Right
width, // Left | Center | Right
]
];
}
}
public equals(other: Settings): boolean {
return (
this.lineHeight === other.lineHeight
&& this.pixelRatio === other.pixelRatio
&& this.overviewRulerLanes === other.overviewRulerLanes
&& this.renderBorder === other.renderBorder
&& this.borderColor === other.borderColor
&& this.hideCursor === other.hideCursor
&& this.cursorColor === other.cursorColor
&& this.themeType === other.themeType
&& this.backgroundColor === other.backgroundColor
&& this.top === other.top
&& this.right === other.right
&& this.domWidth === other.domWidth
&& this.domHeight === other.domHeight
&& this.canvasWidth === other.canvasWidth
&& this.canvasHeight === other.canvasHeight
);
}
}
const enum Constants {
MIN_DECORATION_HEIGHT = 6
}
const enum OverviewRulerLane {
Left = 1,
Center = 2,
Right = 4,
Full = 7
}
export class DecorationsOverviewRuler extends ViewPart {
static MIN_DECORATION_HEIGHT = 6;
static MAX_DECORATION_HEIGHT = 60;
private readonly _tokensColorTrackerListener: IDisposable;
private _overviewRuler: OverviewRulerImpl;
private _renderBorder: boolean;
private _borderColor: string;
private _cursorColor: string;
private _shouldUpdateDecorations: boolean;
private _shouldUpdateCursorPosition: boolean;
private _hideCursor: boolean;
private readonly _domNode: FastDomNode<HTMLCanvasElement>;
private _settings: Settings;
private _cursorPositions: Position[];
private _zonesFromDecorations: OverviewRulerZone[];
private _zonesFromCursors: OverviewRulerZone[];
constructor(context: ViewContext) {
super(context);
this._overviewRuler = new OverviewRulerImpl(
1,
'decorationsOverviewRuler',
this._context.viewLayout.getScrollHeight(),
this._context.configuration.editor.lineHeight,
this._context.configuration.editor.pixelRatio,
DecorationsOverviewRuler.MIN_DECORATION_HEIGHT,
DecorationsOverviewRuler.MAX_DECORATION_HEIGHT,
(lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber)
);
this._overviewRuler.setLanesCount(this._context.configuration.editor.viewInfo.overviewRulerLanes, false);
this._overviewRuler.setLayout(this._context.configuration.editor.layoutInfo.overviewRuler, false);
this._renderBorder = this._context.configuration.editor.viewInfo.overviewRulerBorder;
this._domNode = createFastDomNode(document.createElement('canvas'));
this._domNode.setClassName('decorationsOverviewRuler');
this._domNode.setPosition('absolute');
this._domNode.setLayerHinting(true);
this._updateColors();
this._settings = null;
this._updateSettings(false);
this._updateBackground(false);
this._tokensColorTrackerListener = TokenizationRegistry.onDidChange((e) => {
if (e.changedColorMap) {
this._updateBackground(true);
this._updateSettings(true);
}
});
this._shouldUpdateDecorations = true;
this._zonesFromDecorations = [];
this._shouldUpdateCursorPosition = true;
this._hideCursor = this._context.configuration.editor.viewInfo.hideCursorInOverviewRuler;
this._zonesFromCursors = [];
this._cursorPositions = [];
}
public dispose(): void {
super.dispose();
this._overviewRuler.dispose();
this._tokensColorTrackerListener.dispose();
}
private _updateBackground(render: boolean): void {
const minimapEnabled = this._context.configuration.editor.viewInfo.minimap.enabled;
this._overviewRuler.setUseBackground((minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null), render);
}
// ---- begin view event handlers
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
let prevLanesCount = this._overviewRuler.getLanesCount();
let newLanesCount = this._context.configuration.editor.viewInfo.overviewRulerLanes;
if (prevLanesCount !== newLanesCount) {
this._overviewRuler.setLanesCount(newLanesCount, false);
private _updateSettings(renderNow: boolean): boolean {
const newSettings = new Settings(this._context.configuration, this._context.theme);
if (this._settings !== null && this._settings.equals(newSettings)) {
// nothing to do
return false;
}
if (e.lineHeight) {
this._overviewRuler.setLineHeight(this._context.configuration.editor.lineHeight, false);
}
this._settings = newSettings;
if (e.pixelRatio) {
this._overviewRuler.setPixelRatio(this._context.configuration.editor.pixelRatio, false);
}
this._domNode.setTop(this._settings.top);
this._domNode.setRight(this._settings.right);
this._domNode.setWidth(this._settings.domWidth);
this._domNode.setHeight(this._settings.domHeight);
this._domNode.domNode.width = this._settings.canvasWidth;
this._domNode.domNode.height = this._settings.canvasHeight;
if (e.viewInfo) {
this._renderBorder = this._context.configuration.editor.viewInfo.overviewRulerBorder;
this._hideCursor = this._context.configuration.editor.viewInfo.hideCursorInOverviewRuler;
this._shouldUpdateCursorPosition = true;
this._updateBackground(false);
}
if (e.layoutInfo) {
this._overviewRuler.setLayout(this._context.configuration.editor.layoutInfo.overviewRuler, false);
if (renderNow) {
this._render();
}
return true;
}
// ---- begin view event handlers
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
return this._updateSettings(false);
}
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
this._shouldUpdateCursorPosition = true;
this._cursorPositions = [];
for (let i = 0, len = e.selections.length; i < len; i++) {
this._cursorPositions[i] = e.selections[i].getPosition();
}
return true;
}
public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {
this._shouldUpdateDecorations = true;
return true;
}
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
this._shouldUpdateCursorPosition = true;
this._shouldUpdateDecorations = true;
return true;
}
public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {
this._overviewRuler.setScrollHeight(e.scrollHeight, false);
return super.onScrollChanged(e) || e.scrollHeightChanged;
return e.scrollHeightChanged;
}
public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {
return true;
}
public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {
this._updateColors();
this._shouldUpdateDecorations = true;
this._shouldUpdateCursorPosition = true;
return true;
// invalidate color cache
this._context.model.invalidateOverviewRulerColorCache();
return this._updateSettings(false);
}
// ---- end view event handlers
public getDomNode(): HTMLElement {
return this._overviewRuler.getDomNode();
}
private _updateColors() {
let borderColor = this._context.theme.getColor(editorOverviewRulerBorder);
this._borderColor = borderColor ? borderColor.toString() : null;
let cursorColor = this._context.theme.getColor(editorCursorForeground);
this._cursorColor = cursorColor ? cursorColor.transparent(0.7).toString() : null;
this._overviewRuler.setThemeType(this._context.theme.type, false);
}
private _createZonesFromDecorations(): OverviewRulerZone[] {
let decorations = this._context.model.getAllOverviewRulerDecorations();
let zones: OverviewRulerZone[] = [];
for (let i = 0, len = decorations.length; i < len; i++) {
let dec = decorations[i];
let overviewRuler = dec.source.options.overviewRuler;
zones[i] = new OverviewRulerZone(
dec.range.startLineNumber,
dec.range.endLineNumber,
overviewRuler.position,
0,
this.resolveRulerColor(overviewRuler.color),
this.resolveRulerColor(overviewRuler.darkColor),
this.resolveRulerColor(overviewRuler.hcColor)
);
}
return zones;
}
private resolveRulerColor(color: string | ThemeColor): string {
if (editorCommon.isThemeColor(color)) {
let c = this._context.theme.getColor(color.id) || Color.transparent;
return c.toString();
}
return color;
}
private _createZonesFromCursors(): OverviewRulerZone[] {
let zones: OverviewRulerZone[] = [];
for (let i = 0, len = this._cursorPositions.length; i < len; i++) {
let cursor = this._cursorPositions[i];
zones[i] = new OverviewRulerZone(
cursor.lineNumber,
cursor.lineNumber,
editorCommon.OverviewRulerLane.Full,
2,
this._cursorColor,
this._cursorColor,
this._cursorColor
);
}
return zones;
return this._domNode.domNode;
}
public prepareRender(ctx: RenderingContext): void {
// Nothing to read
}
public render(ctx: RestrictedRenderingContext): void {
if (this._shouldUpdateDecorations || this._shouldUpdateCursorPosition) {
public render(editorCtx: RestrictedRenderingContext): void {
this._render();
}
if (this._shouldUpdateDecorations) {
this._shouldUpdateDecorations = false;
this._zonesFromDecorations = this._createZonesFromDecorations();
}
private _render(): void {
const canvasWidth = this._settings.canvasWidth;
const canvasHeight = this._settings.canvasHeight;
const lineHeight = this._settings.lineHeight;
const viewLayout = this._context.viewLayout;
const outerHeight = this._context.viewLayout.getScrollHeight();
const heightRatio = canvasHeight / outerHeight;
const decorations = this._context.model.getAllOverviewRulerDecorations(this._context.theme);
if (this._shouldUpdateCursorPosition) {
this._shouldUpdateCursorPosition = false;
if (this._hideCursor) {
this._zonesFromCursors = [];
} else {
this._zonesFromCursors = this._createZonesFromCursors();
}
}
const minDecorationHeight = (Constants.MIN_DECORATION_HEIGHT * this._settings.pixelRatio) | 0;
const halfMinDecorationHeight = (minDecorationHeight / 2) | 0;
let allZones: OverviewRulerZone[] = [];
allZones = allZones.concat(this._zonesFromCursors);
allZones = allZones.concat(this._zonesFromDecorations);
this._overviewRuler.setZones(allZones, false);
const canvasCtx = this._domNode.domNode.getContext('2d');
if (this._settings.backgroundColor === null) {
canvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);
} else {
canvasCtx.fillStyle = this._settings.backgroundColor;
canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight);
}
let hasRendered = this._overviewRuler.render(false);
const x = this._settings.x;
const w = this._settings.w;
// Avoid flickering by always rendering the colors in the same order
// colors that don't use transparency will be sorted last (they start with #)
const colors = Object.keys(decorations);
colors.sort();
for (let cIndex = 0, cLen = colors.length; cIndex < cLen; cIndex++) {
const color = colors[cIndex];
if (hasRendered && this._renderBorder && this._borderColor && this._overviewRuler.getLanesCount() > 0 && (this._zonesFromDecorations.length > 0 || this._zonesFromCursors.length > 0)) {
let ctx2 = this._overviewRuler.getDomNode().getContext('2d');
ctx2.beginPath();
ctx2.lineWidth = 1;
ctx2.strokeStyle = this._borderColor;
ctx2.moveTo(0, 0);
ctx2.lineTo(0, this._overviewRuler.getPixelHeight());
ctx2.stroke();
const colorDecorations = decorations[color];
ctx2.moveTo(0, 0);
ctx2.lineTo(this._overviewRuler.getPixelWidth(), 0);
ctx2.stroke();
canvasCtx.fillStyle = color;
let prevLane = 0;
let prevY1 = 0;
let prevY2 = 0;
for (let i = 0, len = colorDecorations.length; i < len; i++) {
const lane = colorDecorations[3 * i];
const startLineNumber = colorDecorations[3 * i + 1];
const endLineNumber = colorDecorations[3 * i + 2];
let y1 = (viewLayout.getVerticalOffsetForLineNumber(startLineNumber) * heightRatio) | 0;
let y2 = ((viewLayout.getVerticalOffsetForLineNumber(endLineNumber) + lineHeight) * heightRatio) | 0;
let height = y2 - y1;
if (height < minDecorationHeight) {
let yCenter = ((y1 + y2) / 2) | 0;
if (yCenter < halfMinDecorationHeight) {
yCenter = halfMinDecorationHeight;
} else if (yCenter + halfMinDecorationHeight > canvasHeight) {
yCenter = canvasHeight - halfMinDecorationHeight;
}
y1 = yCenter - halfMinDecorationHeight;
y2 = yCenter + halfMinDecorationHeight;
}
if (y1 > prevY2 + 1 || lane !== prevLane) {
// flush prev
if (i !== 0) {
canvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1);
}
prevLane = lane;
prevY1 = y1;
prevY2 = y2;
} else {
// merge into prev
if (y2 > prevY2) {
prevY2 = y2;
}
}
}
canvasCtx.fillRect(x[prevLane], prevY1, w[prevLane], prevY2 - prevY1);
}
// Draw cursors
if (!this._settings.hideCursor) {
const cursorHeight = (2 * this._settings.pixelRatio) | 0;
const halfCursorHeight = (cursorHeight / 2) | 0;
const cursorX = this._settings.x[OverviewRulerLane.Full];
const cursorW = this._settings.w[OverviewRulerLane.Full];
canvasCtx.fillStyle = this._settings.cursorColor;
let prevY1 = -100;
let prevY2 = -100;
for (let i = 0, len = this._cursorPositions.length; i < len; i++) {
const cursor = this._cursorPositions[i];
let yCenter = (viewLayout.getVerticalOffsetForLineNumber(cursor.lineNumber) * heightRatio) | 0;
if (yCenter < halfCursorHeight) {
yCenter = halfCursorHeight;
} else if (yCenter + halfCursorHeight > canvasHeight) {
yCenter = canvasHeight - halfCursorHeight;
}
const y1 = yCenter - halfCursorHeight;
const y2 = y1 + cursorHeight;
if (y1 > prevY2 + 1) {
// flush prev
if (i !== 0) {
canvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1);
}
prevY1 = y1;
prevY2 = y2;
} else {
// merge into prev
if (y2 > prevY2) {
prevY2 = y2;
}
}
}
canvasCtx.fillRect(cursorX, prevY1, cursorW, prevY2 - prevY1);
}
if (this._settings.renderBorder && this._settings.borderColor && this._settings.overviewRulerLanes > 0) {
canvasCtx.beginPath();
canvasCtx.lineWidth = 1;
canvasCtx.strokeStyle = this._settings.borderColor;
canvasCtx.moveTo(0, 0);
canvasCtx.lineTo(0, canvasHeight);
canvasCtx.stroke();
canvasCtx.moveTo(0, 0);
canvasCtx.lineTo(canvasWidth, 0);
canvasCtx.stroke();
}
}
}

View File

@@ -30,7 +30,7 @@ import { IPosition } from 'vs/editor/common/core/position';
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer';
import { CoreEditorCommand } from 'vs/editor/common/controller/coreCommands';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder } from 'vs/editor/common/view/editorColorRegistry';
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground } from 'vs/editor/common/view/editorColorRegistry';
import { Color } from 'vs/base/common/color';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
@@ -400,6 +400,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
this._view.render(false, true);
this.hasView = true;
this._view.domNode.domNode.setAttribute('data-uri', model.uri.toString());
}
}
@@ -517,19 +518,28 @@ function getSquigglySVGData(color: Color) {
registerThemingParticipant((theme, collector) => {
let errorBorderColor = theme.getColor(editorErrorBorder);
if (errorBorderColor) {
collector.addRule(`.monaco-editor .redsquiggly { border-bottom: 4px double ${errorBorderColor}; }`);
collector.addRule(`.monaco-editor .errorsquiggly { border-bottom: 4px double ${errorBorderColor}; }`);
}
let errorForeground = theme.getColor(editorErrorForeground);
if (errorForeground) {
collector.addRule(`.monaco-editor .redsquiggly { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`);
collector.addRule(`.monaco-editor .errorsquiggly { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`);
}
let warningBorderColor = theme.getColor(editorWarningBorder);
if (warningBorderColor) {
collector.addRule(`.monaco-editor .greensquiggly { border-bottom: 4px double ${warningBorderColor}; }`);
collector.addRule(`.monaco-editor .warningsquiggly { border-bottom: 4px double ${warningBorderColor}; }`);
}
let warningForeground = theme.getColor(editorWarningForeground);
if (warningForeground) {
collector.addRule(`.monaco-editor .greensquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
collector.addRule(`.monaco-editor .warningsquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
}
let infoBorderColor = theme.getColor(editorInfoBorder);
if (warningBorderColor) {
collector.addRule(`.monaco-editor .infosquiggly { border-bottom: 4px double ${infoBorderColor}; }`);
}
let infoForeground = theme.getColor(editorInfoForeground);
if (warningForeground) {
collector.addRule(`.monaco-editor .infosquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`);
}
});

View File

@@ -11,8 +11,11 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { CodeEditor } from 'vs/editor/browser/codeEditor';
import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IConfigurationChangedEvent, IEditorOptions, IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { IMessageService } from 'vs/platform/message/common/message';
export class EmbeddedCodeEditorWidget extends CodeEditor {
@@ -40,7 +43,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditor {
this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e)));
}
public getParentEditor(): ICodeEditor {
getParentEditor(): ICodeEditor {
return this._parentEditor;
}
@@ -49,7 +52,49 @@ export class EmbeddedCodeEditorWidget extends CodeEditor {
super.updateOptions(this._overwriteOptions);
}
public updateOptions(newOptions: IEditorOptions): void {
updateOptions(newOptions: IEditorOptions): void {
objects.mixin(this._overwriteOptions, newOptions, true);
super.updateOptions(this._overwriteOptions);
}
}
export class EmbeddedDiffEditorWidget extends DiffEditorWidget {
private _parentEditor: ICodeEditor;
private _overwriteOptions: IDiffEditorOptions;
constructor(
domElement: HTMLElement,
options: IDiffEditorOptions,
parentEditor: ICodeEditor,
@IEditorWorkerService editorWorkerService: IEditorWorkerService,
@IContextKeyService contextKeyService: IContextKeyService,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IThemeService themeService: IThemeService,
@IMessageService messageService: IMessageService
) {
super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, messageService);
this._parentEditor = parentEditor;
this._overwriteOptions = options;
// Overwrite parent's options
super.updateOptions(this._overwriteOptions);
this._register(parentEditor.onDidChangeConfiguration(e => this._onParentConfigurationChanged(e)));
}
getParentEditor(): ICodeEditor {
return this._parentEditor;
}
private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void {
super.updateOptions(this._parentEditor.getRawConfiguration());
super.updateOptions(this._overwriteOptions);
}
updateOptions(newOptions: IEditorOptions): void {
objects.mixin(this._overwriteOptions, newOptions, true);
super.updateOptions(this._overwriteOptions);
}