SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,535 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/editor';
import 'vs/css!./media/tokens';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import * as dom from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor';
import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig';
import { Range, IRange } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditorAction } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { Configuration } from 'vs/editor/browser/config/configuration';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
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 { Color } from 'vs/base/common/color';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
private readonly _onMouseUp: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseUp: Event<editorBrowser.IEditorMouseEvent> = this._onMouseUp.event;
private readonly _onMouseDown: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseDown: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDown.event;
private readonly _onMouseDrag: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseDrag: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrag.event;
private readonly _onMouseDrop: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseDrop: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrop.event;
private readonly _onContextMenu: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onContextMenu: Event<editorBrowser.IEditorMouseEvent> = this._onContextMenu.event;
private readonly _onMouseMove: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseMove: Event<editorBrowser.IEditorMouseEvent> = this._onMouseMove.event;
private readonly _onMouseLeave: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
public readonly onMouseLeave: Event<editorBrowser.IEditorMouseEvent> = this._onMouseLeave.event;
private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
private readonly _onKeyDown: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
private readonly _onDidScrollChange: Emitter<editorCommon.IScrollEvent> = this._register(new Emitter<editorCommon.IScrollEvent>());
public readonly onDidScrollChange: Event<editorCommon.IScrollEvent> = this._onDidScrollChange.event;
private readonly _onDidChangeViewZones: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeViewZones: Event<void> = this._onDidChangeViewZones.event;
private _codeEditorService: ICodeEditorService;
private _commandService: ICommandService;
private _themeService: IThemeService;
protected domElement: HTMLElement;
private _focusTracker: CodeEditorWidgetFocusTracker;
_configuration: Configuration;
private contentWidgets: { [key: string]: IContentWidgetData; };
private overlayWidgets: { [key: string]: IOverlayWidgetData; };
_view: View;
constructor(
domElement: HTMLElement,
options: IEditorOptions,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@ICommandService commandService: ICommandService,
@IContextKeyService contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService
) {
super(domElement, options, instantiationService, contextKeyService);
this._codeEditorService = codeEditorService;
this._commandService = commandService;
this._themeService = themeService;
this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
this._focusTracker.onChange(() => {
let hasFocus = this._focusTracker.hasFocus();
if (hasFocus) {
this._onDidFocusEditor.fire();
} else {
this._onDidBlurEditor.fire();
}
});
this.contentWidgets = {};
this.overlayWidgets = {};
let contributions = this._getContributions();
for (let i = 0, len = contributions.length; i < len; i++) {
let ctor = contributions[i];
try {
let contribution = this._instantiationService.createInstance(ctor, this);
this._contributions[contribution.getId()] = contribution;
} catch (err) {
onUnexpectedError(err);
}
}
this._getActions().forEach((action) => {
const internalAction = new InternalEditorAction(
action.id,
action.label,
action.alias,
action.precondition,
(): void | TPromise<void> => {
return this._instantiationService.invokeFunction((accessor) => {
return action.runEditorCommand(accessor, this, null);
});
},
this._contextKeyService
);
this._actions[internalAction.id] = internalAction;
});
this._codeEditorService.addCodeEditor(this);
}
protected abstract _getContributions(): editorBrowser.IEditorContributionCtor[];
protected abstract _getActions(): EditorAction[];
protected _createConfiguration(options: IEditorOptions): CommonEditorConfiguration {
return new Configuration(options, this.domElement);
}
public dispose(): void {
this._codeEditorService.removeCodeEditor(this);
this.contentWidgets = {};
this.overlayWidgets = {};
this._focusTracker.dispose();
super.dispose();
}
public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): editorBrowser.IOverviewRuler {
return this._view.createOverviewRuler(cssClassName, minimumHeight, maximumHeight);
}
public getDomNode(): HTMLElement {
if (!this.hasView) {
return null;
}
return this._view.domNode.domNode;
}
public getCompletelyVisibleLinesRangeInViewport(): Range {
if (!this.hasView) {
return null;
}
const viewRange = this.viewModel.getCompletelyVisibleViewRange();
return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
}
public delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {
if (!this.hasView) {
return;
}
this._view.delegateVerticalScrollbarMouseDown(browserEvent);
}
public layout(dimension?: editorCommon.IDimension): void {
this._configuration.observeReferenceElement(dimension);
this.render();
}
public focus(): void {
if (!this.hasView) {
return;
}
this._view.focus();
}
public isFocused(): boolean {
return this.hasView && this._view.isFocused();
}
public hasWidgetFocus(): boolean {
return this._focusTracker && this._focusTracker.hasFocus();
}
public addContentWidget(widget: editorBrowser.IContentWidget): void {
let widgetData: IContentWidgetData = {
widget: widget,
position: widget.getPosition()
};
if (this.contentWidgets.hasOwnProperty(widget.getId())) {
console.warn('Overwriting a content widget with the same id.');
}
this.contentWidgets[widget.getId()] = widgetData;
if (this.hasView) {
this._view.addContentWidget(widgetData);
}
}
public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
let widgetId = widget.getId();
if (this.contentWidgets.hasOwnProperty(widgetId)) {
let widgetData = this.contentWidgets[widgetId];
widgetData.position = widget.getPosition();
if (this.hasView) {
this._view.layoutContentWidget(widgetData);
}
}
}
public removeContentWidget(widget: editorBrowser.IContentWidget): void {
let widgetId = widget.getId();
if (this.contentWidgets.hasOwnProperty(widgetId)) {
let widgetData = this.contentWidgets[widgetId];
delete this.contentWidgets[widgetId];
if (this.hasView) {
this._view.removeContentWidget(widgetData);
}
}
}
public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
let widgetData: IOverlayWidgetData = {
widget: widget,
position: widget.getPosition()
};
if (this.overlayWidgets.hasOwnProperty(widget.getId())) {
console.warn('Overwriting an overlay widget with the same id.');
}
this.overlayWidgets[widget.getId()] = widgetData;
if (this.hasView) {
this._view.addOverlayWidget(widgetData);
}
}
public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
let widgetId = widget.getId();
if (this.overlayWidgets.hasOwnProperty(widgetId)) {
let widgetData = this.overlayWidgets[widgetId];
widgetData.position = widget.getPosition();
if (this.hasView) {
this._view.layoutOverlayWidget(widgetData);
}
}
}
public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
let widgetId = widget.getId();
if (this.overlayWidgets.hasOwnProperty(widgetId)) {
let widgetData = this.overlayWidgets[widgetId];
delete this.overlayWidgets[widgetId];
if (this.hasView) {
this._view.removeOverlayWidget(widgetData);
}
}
}
public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
if (!this.hasView) {
return;
}
let hasChanges = this._view.change(callback);
if (hasChanges) {
this._onDidChangeViewZones.fire();
}
}
public getWhitespaces(): IEditorWhitespace[] {
if (!this.hasView) {
return [];
}
return this.viewModel.viewLayout.getWhitespaces();
}
private _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number {
let modelPosition = this.model.validatePosition({
lineNumber: modelLineNumber,
column: modelColumn
});
let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
}
public getTopForLineNumber(lineNumber: number): number {
if (!this.hasView) {
return -1;
}
return this._getVerticalOffsetForPosition(lineNumber, 1);
}
public getTopForPosition(lineNumber: number, column: number): number {
if (!this.hasView) {
return -1;
}
return this._getVerticalOffsetForPosition(lineNumber, column);
}
public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
if (!this.hasView) {
return null;
}
return this._view.getTargetAtClientPoint(clientX, clientY);
}
public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
if (!this.hasView) {
return null;
}
let position = this.model.validatePosition(rawPosition);
let layoutInfo = this._configuration.editor.layoutInfo;
let top = this._getVerticalOffsetForPosition(position.lineNumber, position.column) - this.getScrollTop();
let left = this._view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft();
return {
top: top,
left: left,
height: this._configuration.editor.lineHeight
};
}
public getOffsetForColumn(lineNumber: number, column: number): number {
if (!this.hasView) {
return -1;
}
return this._view.getOffsetForColumn(lineNumber, column);
}
public render(): void {
if (!this.hasView) {
return;
}
this._view.render(true, false);
}
public setHiddenAreas(ranges: IRange[]): void {
if (this.viewModel) {
this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));
}
}
public setAriaActiveDescendant(id: string): void {
if (!this.hasView) {
return;
}
this._view.setAriaActiveDescendant(id);
}
public applyFontInfo(target: HTMLElement): void {
Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
}
_attachModel(model: editorCommon.IModel): void {
this._view = null;
super._attachModel(model);
if (this._view) {
this.domElement.appendChild(this._view.domNode.domNode);
let keys = Object.keys(this.contentWidgets);
for (let i = 0, len = keys.length; i < len; i++) {
let widgetId = keys[i];
this._view.addContentWidget(this.contentWidgets[widgetId]);
}
keys = Object.keys(this.overlayWidgets);
for (let i = 0, len = keys.length; i < len; i++) {
let widgetId = keys[i];
this._view.addOverlayWidget(this.overlayWidgets[widgetId]);
}
this._view.render(false, true);
this.hasView = true;
}
}
protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable {
return dom.scheduleAtNextAnimationFrame(callback);
}
protected _createView(): void {
this._view = new View(
this._commandService,
this._configuration,
this._themeService,
this.viewModel,
this.cursor,
(editorCommand: CoreEditorCommand, args: any) => {
if (!this.cursor) {
return;
}
editorCommand.runCoreEditorCommand(this.cursor, args);
}
);
const viewEventBus = this._view.getInternalEventBus();
viewEventBus.onDidGainFocus = () => {
this._onDidFocusEditorText.fire();
// In IE, the focus is not synchronous, so we give it a little help
this._onDidFocusEditor.fire();
};
viewEventBus.onDidScroll = (e) => this._onDidScrollChange.fire(e);
viewEventBus.onDidLoseFocus = () => this._onDidBlurEditorText.fire();
viewEventBus.onContextMenu = (e) => this._onContextMenu.fire(e);
viewEventBus.onMouseDown = (e) => this._onMouseDown.fire(e);
viewEventBus.onMouseUp = (e) => this._onMouseUp.fire(e);
viewEventBus.onMouseDrag = (e) => this._onMouseDrag.fire(e);
viewEventBus.onMouseDrop = (e) => this._onMouseDrop.fire(e);
viewEventBus.onKeyUp = (e) => this._onKeyUp.fire(e);
viewEventBus.onMouseMove = (e) => this._onMouseMove.fire(e);
viewEventBus.onMouseLeave = (e) => this._onMouseLeave.fire(e);
viewEventBus.onKeyDown = (e) => this._onKeyDown.fire(e);
}
protected _detachModel(): editorCommon.IModel {
let removeDomNode: HTMLElement = null;
if (this._view) {
this._view.dispose();
removeDomNode = this._view.domNode.domNode;
this._view = null;
}
let result = super._detachModel();
if (removeDomNode) {
this.domElement.removeChild(removeDomNode);
}
return result;
}
// BEGIN decorations
protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
}
protected _removeDecorationType(key: string): void {
this._codeEditorService.removeDecorationType(key);
}
protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
}
// END decorations
}
class CodeEditorWidgetFocusTracker extends Disposable {
private _hasFocus: boolean;
private _domFocusTracker: dom.IFocusTracker;
private _onChange: Emitter<void> = this._register(new Emitter<void>());
public onChange: Event<void> = this._onChange.event;
constructor(domElement: HTMLElement) {
super();
this._hasFocus = false;
this._domFocusTracker = this._register(dom.trackFocus(domElement));
this._domFocusTracker.addFocusListener(() => {
this._hasFocus = true;
this._onChange.fire(void 0);
});
this._domFocusTracker.addBlurListener(() => {
this._hasFocus = false;
this._onChange.fire(void 0);
});
}
public hasFocus(): boolean {
return this._hasFocus;
}
}
const squigglyStart = encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' height='3' width='6'><g fill='`);
const squigglyEnd = encodeURIComponent(`'><polygon points='5.5,0 2.5,3 1.1,3 4.1,0'/><polygon points='4,0 6,2 6,0.6 5.4,0'/><polygon points='0,2 1,3 2.4,3 0,0.6'/></g></svg>`);
function getSquigglySVGData(color: Color) {
return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
}
registerThemingParticipant((theme, collector) => {
let errorBorderColor = theme.getColor(editorErrorBorder);
if (errorBorderColor) {
collector.addRule(`.monaco-editor .redsquiggly { 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; }`);
}
let warningBorderColor = theme.getColor(editorWarningBorder);
if (warningBorderColor) {
collector.addRule(`.monaco-editor .greensquiggly { 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; }`);
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'vs/base/common/assert';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import * as objects from 'vs/base/common/objects';
import { Range } from 'vs/editor/common/core/range';
import { ICommonDiffEditor, ILineChange, ScrollType } from 'vs/editor/common/editorCommon';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
interface IDiffRange {
rhs: boolean;
range: Range;
}
export interface Options {
followsCaret?: boolean;
ignoreCharChanges?: boolean;
alwaysRevealFirst?: boolean;
}
var defaultOptions: Options = {
followsCaret: true,
ignoreCharChanges: true,
alwaysRevealFirst: true
};
/**
* Create a new diff navigator for the provided diff editor.
*/
export class DiffNavigator extends EventEmitter {
public static Events = {
UPDATED: 'navigation.updated'
};
private editor: ICommonDiffEditor;
private options: Options;
private disposed: boolean;
private toUnbind: IDisposable[];
private nextIdx: number;
private ranges: IDiffRange[];
private ignoreSelectionChange: boolean;
public revealFirst: boolean;
constructor(editor: ICommonDiffEditor, options: Options = {}) {
super([
DiffNavigator.Events.UPDATED
]);
this.editor = editor;
this.options = objects.mixin(options, defaultOptions, false);
this.disposed = false;
this.toUnbind = [];
this.nextIdx = -1;
this.ranges = [];
this.ignoreSelectionChange = false;
this.revealFirst = this.options.alwaysRevealFirst;
// hook up to diff editor for diff, disposal, and caret move
this.toUnbind.push(this.editor.onDidDispose(() => this.dispose()));
this.toUnbind.push(this.editor.onDidUpdateDiff(() => this.onDiffUpdated()));
if (this.options.followsCaret) {
this.toUnbind.push(this.editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {
if (this.ignoreSelectionChange) {
return;
}
this.nextIdx = -1;
}));
}
if (this.options.alwaysRevealFirst) {
this.toUnbind.push(this.editor.getModifiedEditor().onDidChangeModel((e) => {
this.revealFirst = true;
}));
}
// init things
this.init();
}
private init(): void {
var changes = this.editor.getLineChanges();
if (!changes) {
return;
}
}
private onDiffUpdated(): void {
this.init();
this.compute(this.editor.getLineChanges());
if (this.revealFirst) {
// Only reveal first on first non-null changes
if (this.editor.getLineChanges() !== null) {
this.revealFirst = false;
this.nextIdx = -1;
this.next();
}
}
}
private compute(lineChanges: ILineChange[]): void {
// new ranges
this.ranges = [];
if (lineChanges) {
// create ranges from changes
lineChanges.forEach((lineChange) => {
if (!this.options.ignoreCharChanges && lineChange.charChanges) {
lineChange.charChanges.forEach((charChange) => {
this.ranges.push({
rhs: true,
range: new Range(
charChange.modifiedStartLineNumber,
charChange.modifiedStartColumn,
charChange.modifiedEndLineNumber,
charChange.modifiedEndColumn)
});
});
} else {
this.ranges.push({
rhs: true,
range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedStartLineNumber, 1)
});
}
});
}
// sort
this.ranges.sort((left, right) => {
if (left.range.getStartPosition().isBeforeOrEqual(right.range.getStartPosition())) {
return -1;
} else if (right.range.getStartPosition().isBeforeOrEqual(left.range.getStartPosition())) {
return 1;
} else {
return 0;
}
});
this.emit(DiffNavigator.Events.UPDATED, {});
}
private initIdx(fwd: boolean): void {
var found = false;
var position = this.editor.getPosition();
for (var i = 0, len = this.ranges.length; i < len && !found; i++) {
var range = this.ranges[i].range;
if (position.isBeforeOrEqual(range.getStartPosition())) {
this.nextIdx = i + (fwd ? 0 : -1);
found = true;
}
}
if (!found) {
// after the last change
this.nextIdx = fwd ? 0 : this.ranges.length - 1;
}
if (this.nextIdx < 0) {
this.nextIdx = this.ranges.length - 1;
}
}
private move(fwd: boolean): void {
assert.ok(!this.disposed, 'Illegal State - diff navigator has been disposed');
if (!this.canNavigate()) {
return;
}
if (this.nextIdx === -1) {
this.initIdx(fwd);
} else if (fwd) {
this.nextIdx += 1;
if (this.nextIdx >= this.ranges.length) {
this.nextIdx = 0;
}
} else {
this.nextIdx -= 1;
if (this.nextIdx < 0) {
this.nextIdx = this.ranges.length - 1;
}
}
var info = this.ranges[this.nextIdx];
this.ignoreSelectionChange = true;
try {
var pos = info.range.getStartPosition();
this.editor.setPosition(pos);
this.editor.revealPositionInCenter(pos, ScrollType.Smooth);
} finally {
this.ignoreSelectionChange = false;
}
}
public canNavigate(): boolean {
return this.ranges && this.ranges.length > 0;
}
public next(): void {
this.move(true);
}
public previous(): void {
this.move(false);
}
public dispose(): void {
this.toUnbind = dispose(this.toUnbind);
this.ranges = null;
this.disposed = true;
super.dispose();
}
}

View File

@@ -0,0 +1,822 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/diffReview';
import * as nls from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import * as dom from 'vs/base/browser/dom';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { renderViewLine2 as renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { Position } from 'vs/editor/common/core/position';
import { ColorId, MetadataConsts, FontStyle } from 'vs/editor/common/modes';
import * as editorOptions from 'vs/editor/common/config/editorOptions';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { editorAction, EditorAction, ServicesAccessor } from 'vs/editor/common/editorCommonExtensions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
const DIFF_LINES_PADDING = 3;
const enum DiffEntryType {
Equal = 0,
Insert = 1,
Delete = 2
}
class DiffEntry {
readonly originalLineStart: number;
readonly originalLineEnd: number;
readonly modifiedLineStart: number;
readonly modifiedLineEnd: number;
constructor(originalLineStart: number, originalLineEnd: number, modifiedLineStart: number, modifiedLineEnd: number) {
this.originalLineStart = originalLineStart;
this.originalLineEnd = originalLineEnd;
this.modifiedLineStart = modifiedLineStart;
this.modifiedLineEnd = modifiedLineEnd;
}
public getType(): DiffEntryType {
if (this.originalLineStart === 0) {
return DiffEntryType.Insert;
}
if (this.modifiedLineStart === 0) {
return DiffEntryType.Delete;
}
return DiffEntryType.Equal;
}
}
class Diff {
readonly entries: DiffEntry[];
constructor(entries: DiffEntry[]) {
this.entries = entries;
}
}
export class DiffReview extends Disposable {
private readonly _diffEditor: DiffEditorWidget;
private _isVisible: boolean;
public readonly shadow: FastDomNode<HTMLElement>;
private readonly _actionBar: ActionBar;
public readonly actionBarContainer: FastDomNode<HTMLElement>;
public readonly domNode: FastDomNode<HTMLElement>;
private readonly _content: FastDomNode<HTMLElement>;
private readonly scrollbar: DomScrollableElement;
private _diffs: Diff[];
private _currentDiff: Diff;
constructor(diffEditor: DiffEditorWidget) {
super();
this._diffEditor = diffEditor;
this._isVisible = false;
this.shadow = createFastDomNode(document.createElement('div'));
this.shadow.setClassName('diff-review-shadow');
this.actionBarContainer = createFastDomNode(document.createElement('div'));
this.actionBarContainer.setClassName('diff-review-actions');
this._actionBar = this._register(new ActionBar(
this.actionBarContainer.domNode
));
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review', true, () => {
this.hide();
return null;
}), { label: false, icon: true });
this.domNode = createFastDomNode(document.createElement('div'));
this.domNode.setClassName('diff-review monaco-editor-background');
this._content = createFastDomNode(document.createElement('div'));
this._content.setClassName('diff-review-content');
this.scrollbar = this._register(new DomScrollableElement(this._content.domNode, {}));
this.domNode.domNode.appendChild(this.scrollbar.getDomNode());
this._register(diffEditor.onDidUpdateDiff(() => {
if (!this._isVisible) {
return;
}
this._diffs = this._compute();
this._render();
}));
this._register(diffEditor.getModifiedEditor().onDidChangeCursorPosition(() => {
if (!this._isVisible) {
return;
}
this._render();
}));
this._register(diffEditor.getOriginalEditor().onDidFocusEditor(() => {
if (this._isVisible) {
this.hide();
}
}));
this._register(diffEditor.getModifiedEditor().onDidFocusEditor(() => {
if (this._isVisible) {
this.hide();
}
}));
this._register(dom.addStandardDisposableListener(this.domNode.domNode, 'click', (e) => {
e.preventDefault();
let row = dom.findParentWithClass(e.target, 'diff-review-row');
if (row) {
this._goToRow(row);
}
}));
this._register(dom.addStandardDisposableListener(this.domNode.domNode, 'keydown', (e) => {
if (
e.equals(KeyCode.DownArrow)
|| e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)
|| e.equals(KeyMod.Alt | KeyCode.DownArrow)
) {
e.preventDefault();
this._goToRow(this._getNextRow());
}
if (
e.equals(KeyCode.UpArrow)
|| e.equals(KeyMod.CtrlCmd | KeyCode.UpArrow)
|| e.equals(KeyMod.Alt | KeyCode.UpArrow)
) {
e.preventDefault();
this._goToRow(this._getPrevRow());
}
if (
e.equals(KeyCode.Escape)
|| e.equals(KeyMod.CtrlCmd | KeyCode.Escape)
|| e.equals(KeyMod.Alt | KeyCode.Escape)
|| e.equals(KeyMod.Shift | KeyCode.Escape)
) {
e.preventDefault();
this.hide();
}
if (
e.equals(KeyCode.Space)
|| e.equals(KeyCode.Enter)
) {
e.preventDefault();
this.accept();
}
}));
this._diffs = [];
this._currentDiff = null;
}
public prev(): void {
let index = 0;
if (!this._isVisible) {
this._diffs = this._compute();
}
if (this._isVisible) {
let currentIndex = -1;
for (let i = 0, len = this._diffs.length; i < len; i++) {
if (this._diffs[i] === this._currentDiff) {
currentIndex = i;
break;
}
}
index = (this._diffs.length + currentIndex - 1);
} else {
index = this._findDiffIndex(this._diffEditor.getPosition());
}
if (this._diffs.length === 0) {
// Nothing to do
return;
}
index = index % this._diffs.length;
this._diffEditor.setPosition(new Position(this._diffs[index].entries[0].modifiedLineStart, 1));
this._isVisible = true;
this._diffEditor.doLayout();
this._render();
this._goToRow(this._getNextRow());
}
public next(): void {
let index = 0;
if (!this._isVisible) {
this._diffs = this._compute();
}
if (this._isVisible) {
let currentIndex = -1;
for (let i = 0, len = this._diffs.length; i < len; i++) {
if (this._diffs[i] === this._currentDiff) {
currentIndex = i;
break;
}
}
index = (currentIndex + 1);
} else {
index = this._findDiffIndex(this._diffEditor.getPosition());
}
if (this._diffs.length === 0) {
// Nothing to do
return;
}
index = index % this._diffs.length;
this._diffEditor.setPosition(new Position(this._diffs[index].entries[0].modifiedLineStart, 1));
this._isVisible = true;
this._diffEditor.doLayout();
this._render();
this._goToRow(this._getNextRow());
}
private accept(): void {
let jumpToLineNumber = -1;
let current = this._getCurrentFocusedRow();
if (current) {
let lineNumber = parseInt(current.getAttribute('data-line'), 10);
if (!isNaN(lineNumber)) {
jumpToLineNumber = lineNumber;
}
}
this.hide();
if (jumpToLineNumber !== -1) {
this._diffEditor.setPosition(new Position(jumpToLineNumber, 1));
this._diffEditor.revealPosition(new Position(jumpToLineNumber, 1), editorCommon.ScrollType.Immediate);
}
}
private hide(): void {
this._isVisible = false;
this._diffEditor.focus();
this._diffEditor.doLayout();
this._render();
}
private _getPrevRow(): HTMLElement {
let current = this._getCurrentFocusedRow();
if (!current) {
return this._getFirstRow();
}
if (current.previousElementSibling) {
return <HTMLElement>current.previousElementSibling;
}
return current;
}
private _getNextRow(): HTMLElement {
let current = this._getCurrentFocusedRow();
if (!current) {
return this._getFirstRow();
}
if (current.nextElementSibling) {
return <HTMLElement>current.nextElementSibling;
}
return current;
}
private _getFirstRow(): HTMLElement {
return <HTMLElement>this.domNode.domNode.querySelector('.diff-review-row');
}
private _getCurrentFocusedRow(): HTMLElement {
let result = <HTMLElement>document.activeElement;
if (result && /diff-review-row/.test(result.className)) {
return result;
}
return null;
}
private _goToRow(row: HTMLElement): void {
let prev = this._getCurrentFocusedRow();
row.tabIndex = 0;
row.focus();
if (prev && prev !== row) {
prev.tabIndex = -1;
}
this.scrollbar.scanDomNode();
}
public isVisible(): boolean {
return this._isVisible;
}
private _width: number = 0;
public layout(top: number, width: number, height: number): void {
this._width = width;
this.shadow.setTop(top - 6);
this.shadow.setWidth(width);
this.shadow.setHeight(this._isVisible ? 6 : 0);
this.domNode.setTop(top);
this.domNode.setWidth(width);
this.domNode.setHeight(height);
this._content.setHeight(height);
this._content.setWidth(width);
if (this._isVisible) {
this.actionBarContainer.setAttribute('aria-hidden', 'false');
this.actionBarContainer.setDisplay('block');
} else {
this.actionBarContainer.setAttribute('aria-hidden', 'true');
this.actionBarContainer.setDisplay('none');
}
}
private _compute(): Diff[] {
const lineChanges = this._diffEditor.getLineChanges();
if (!lineChanges || lineChanges.length === 0) {
return [];
}
const originalModel = this._diffEditor.getOriginalEditor().getModel();
const modifiedModel = this._diffEditor.getModifiedEditor().getModel();
if (!originalModel || !modifiedModel) {
return [];
}
return DiffReview._mergeAdjacent(lineChanges, originalModel.getLineCount(), modifiedModel.getLineCount());
}
private static _mergeAdjacent(lineChanges: editorCommon.ILineChange[], originalLineCount: number, modifiedLineCount: number): Diff[] {
if (!lineChanges || lineChanges.length === 0) {
return [];
}
let diffs: Diff[] = [], diffsLength = 0;
for (let i = 0, len = lineChanges.length; i < len; i++) {
const lineChange = lineChanges[i];
const originalStart = lineChange.originalStartLineNumber;
const originalEnd = lineChange.originalEndLineNumber;
const modifiedStart = lineChange.modifiedStartLineNumber;
const modifiedEnd = lineChange.modifiedEndLineNumber;
let r: DiffEntry[] = [], rLength = 0;
// Emit before anchors
{
const originalEqualAbove = (originalEnd === 0 ? originalStart : originalStart - 1);
const modifiedEqualAbove = (modifiedEnd === 0 ? modifiedStart : modifiedStart - 1);
// Make sure we don't step into the previous diff
let minOriginal = 1;
let minModified = 1;
if (i > 0) {
const prevLineChange = lineChanges[i - 1];
if (prevLineChange.originalEndLineNumber === 0) {
minOriginal = prevLineChange.originalStartLineNumber + 1;
} else {
minOriginal = prevLineChange.originalEndLineNumber + 1;
}
if (prevLineChange.modifiedEndLineNumber === 0) {
minModified = prevLineChange.modifiedStartLineNumber + 1;
} else {
minModified = prevLineChange.modifiedEndLineNumber + 1;
}
}
let fromOriginal = originalEqualAbove - DIFF_LINES_PADDING + 1;
let fromModified = modifiedEqualAbove - DIFF_LINES_PADDING + 1;
if (fromOriginal < minOriginal) {
const delta = minOriginal - fromOriginal;
fromOriginal = fromOriginal + delta;
fromModified = fromModified + delta;
}
if (fromModified < minModified) {
const delta = minModified - fromModified;
fromOriginal = fromOriginal + delta;
fromModified = fromModified + delta;
}
r[rLength++] = new DiffEntry(
fromOriginal, originalEqualAbove,
fromModified, modifiedEqualAbove
);
}
// Emit deleted lines
{
if (originalEnd !== 0) {
r[rLength++] = new DiffEntry(originalStart, originalEnd, 0, 0);
}
}
// Emit inserted lines
{
if (modifiedEnd !== 0) {
r[rLength++] = new DiffEntry(0, 0, modifiedStart, modifiedEnd);
}
}
// Emit after anchors
{
const originalEqualBelow = (originalEnd === 0 ? originalStart + 1 : originalEnd + 1);
const modifiedEqualBelow = (modifiedEnd === 0 ? modifiedStart + 1 : modifiedEnd + 1);
// Make sure we don't step into the next diff
let maxOriginal = originalLineCount;
let maxModified = modifiedLineCount;
if (i + 1 < len) {
const nextLineChange = lineChanges[i + 1];
if (nextLineChange.originalEndLineNumber === 0) {
maxOriginal = nextLineChange.originalStartLineNumber;
} else {
maxOriginal = nextLineChange.originalStartLineNumber - 1;
}
if (nextLineChange.modifiedEndLineNumber === 0) {
maxModified = nextLineChange.modifiedStartLineNumber;
} else {
maxModified = nextLineChange.modifiedStartLineNumber - 1;
}
}
let toOriginal = originalEqualBelow + DIFF_LINES_PADDING - 1;
let toModified = modifiedEqualBelow + DIFF_LINES_PADDING - 1;
if (toOriginal > maxOriginal) {
const delta = maxOriginal - toOriginal;
toOriginal = toOriginal + delta;
toModified = toModified + delta;
}
if (toModified > maxModified) {
const delta = maxModified - toModified;
toOriginal = toOriginal + delta;
toModified = toModified + delta;
}
r[rLength++] = new DiffEntry(
originalEqualBelow, toOriginal,
modifiedEqualBelow, toModified,
);
}
diffs[diffsLength++] = new Diff(r);
}
// Merge adjacent diffs
let curr: DiffEntry[] = diffs[0].entries;
let r: Diff[] = [], rLength = 0;
for (let i = 1, len = diffs.length; i < len; i++) {
const thisDiff = diffs[i].entries;
const currLast = curr[curr.length - 1];
const thisFirst = thisDiff[0];
if (
currLast.getType() === DiffEntryType.Equal
&& thisFirst.getType() === DiffEntryType.Equal
&& thisFirst.originalLineStart <= currLast.originalLineEnd
) {
// We are dealing with equal lines that overlap
curr[curr.length - 1] = new DiffEntry(
currLast.originalLineStart, thisFirst.originalLineEnd,
currLast.modifiedLineStart, thisFirst.modifiedLineEnd
);
curr = curr.concat(thisDiff.slice(1));
continue;
}
r[rLength++] = new Diff(curr);
curr = thisDiff;
}
r[rLength++] = new Diff(curr);
return r;
}
private _findDiffIndex(pos: Position): number {
const lineNumber = pos.lineNumber;
for (let i = 0, len = this._diffs.length; i < len; i++) {
const diff = this._diffs[i].entries;
const lastModifiedLine = diff[diff.length - 1].modifiedLineEnd;
if (lineNumber <= lastModifiedLine) {
return i;
}
}
return 0;
}
private _render(): void {
const originalOpts = this._diffEditor.getOriginalEditor().getConfiguration();
const modifiedOpts = this._diffEditor.getModifiedEditor().getConfiguration();
const originalModel = this._diffEditor.getOriginalEditor().getModel();
const modifiedModel = this._diffEditor.getModifiedEditor().getModel();
const originalModelOpts = originalModel.getOptions();
const modifiedModelOpts = modifiedModel.getOptions();
if (!this._isVisible || !originalModel || !modifiedModel) {
dom.clearNode(this._content.domNode);
this._currentDiff = null;
this.scrollbar.scanDomNode();
return;
}
const pos = this._diffEditor.getPosition();
const diffIndex = this._findDiffIndex(pos);
if (this._diffs[diffIndex] === this._currentDiff) {
return;
}
this._currentDiff = this._diffs[diffIndex];
const diffs = this._diffs[diffIndex].entries;
let container = document.createElement('div');
container.className = 'diff-review-table';
container.setAttribute('role', 'list');
Configuration.applyFontInfoSlow(container, modifiedOpts.fontInfo);
let minOriginalLine = 0;
let maxOriginalLine = 0;
let minModifiedLine = 0;
let maxModifiedLine = 0;
for (let i = 0, len = diffs.length; i < len; i++) {
const diffEntry = diffs[i];
const originalLineStart = diffEntry.originalLineStart;
const originalLineEnd = diffEntry.originalLineEnd;
const modifiedLineStart = diffEntry.modifiedLineStart;
const modifiedLineEnd = diffEntry.modifiedLineEnd;
if (originalLineStart !== 0 && ((minOriginalLine === 0 || originalLineStart < minOriginalLine))) {
minOriginalLine = originalLineStart;
}
if (originalLineEnd !== 0 && ((maxOriginalLine === 0 || originalLineEnd > maxOriginalLine))) {
maxOriginalLine = originalLineEnd;
}
if (modifiedLineStart !== 0 && ((minModifiedLine === 0 || modifiedLineStart < minModifiedLine))) {
minModifiedLine = modifiedLineStart;
}
if (modifiedLineEnd !== 0 && ((maxModifiedLine === 0 || modifiedLineEnd > maxModifiedLine))) {
maxModifiedLine = modifiedLineEnd;
}
}
let header = document.createElement('div');
header.className = 'diff-review-row';
let cell = document.createElement('div');
cell.className = 'diff-review-cell diff-review-summary';
cell.appendChild(document.createTextNode(`${diffIndex + 1}/${this._diffs.length}: @@ -${minOriginalLine},${maxOriginalLine - minOriginalLine + 1} +${minModifiedLine},${maxModifiedLine - minModifiedLine + 1} @@`));
header.setAttribute('data-line', String(minModifiedLine));
header.setAttribute('aria-label', nls.localize('header', "Difference {0} of {1}: original {2}, {3} lines, modified {4}, {5} lines", (diffIndex + 1), this._diffs.length, minOriginalLine, maxOriginalLine - minOriginalLine + 1, minModifiedLine, maxModifiedLine - minModifiedLine + 1));
header.appendChild(cell);
// @@ -504,7 +517,7 @@
header.setAttribute('role', 'listitem');
container.appendChild(header);
let modLine = minModifiedLine;
for (let i = 0, len = diffs.length; i < len; i++) {
const diffEntry = diffs[i];
DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOpts, originalModel, originalModelOpts, modifiedOpts, modifiedModel, modifiedModelOpts);
if (diffEntry.modifiedLineStart !== 0) {
modLine = diffEntry.modifiedLineEnd;
}
}
dom.clearNode(this._content.domNode);
this._content.domNode.appendChild(container);
this.scrollbar.scanDomNode();
}
private static _renderSection(
dest: HTMLElement, diffEntry: DiffEntry, modLine: number, width: number,
originalOpts: editorOptions.InternalEditorOptions, originalModel: editorCommon.IModel, originalModelOpts: editorCommon.TextModelResolvedOptions,
modifiedOpts: editorOptions.InternalEditorOptions, modifiedModel: editorCommon.IModel, modifiedModelOpts: editorCommon.TextModelResolvedOptions
): void {
const type = diffEntry.getType();
let rowClassName: string = 'diff-review-row';
let lineNumbersExtraClassName: string = '';
let spacerClassName: string = 'diff-review-spacer';
switch (type) {
case DiffEntryType.Insert:
rowClassName = 'diff-review-row line-insert';
lineNumbersExtraClassName = ' char-insert';
spacerClassName = 'diff-review-spacer insert-sign';
break;
case DiffEntryType.Delete:
rowClassName = 'diff-review-row line-delete';
lineNumbersExtraClassName = ' char-delete';
spacerClassName = 'diff-review-spacer delete-sign';
break;
}
const originalLineStart = diffEntry.originalLineStart;
const originalLineEnd = diffEntry.originalLineEnd;
const modifiedLineStart = diffEntry.modifiedLineStart;
const modifiedLineEnd = diffEntry.modifiedLineEnd;
const cnt = Math.max(
modifiedLineEnd - modifiedLineStart,
originalLineEnd - originalLineStart
);
const originalLineNumbersWidth = originalOpts.layoutInfo.glyphMarginWidth + originalOpts.layoutInfo.lineNumbersWidth;
const modifiedLineNumbersWidth = 10 + modifiedOpts.layoutInfo.glyphMarginWidth + modifiedOpts.layoutInfo.lineNumbersWidth;
for (let i = 0; i <= cnt; i++) {
const originalLine = (originalLineStart === 0 ? 0 : originalLineStart + i);
const modifiedLine = (modifiedLineStart === 0 ? 0 : modifiedLineStart + i);
const row = document.createElement('div');
row.style.minWidth = width + 'px';
row.className = rowClassName;
row.setAttribute('role', 'listitem');
if (modifiedLine !== 0) {
modLine = modifiedLine;
}
row.setAttribute('data-line', String(modLine));
let cell = document.createElement('div');
cell.className = 'diff-review-cell';
row.appendChild(cell);
const originalLineNumber = document.createElement('span');
originalLineNumber.style.width = (originalLineNumbersWidth + 'px');
originalLineNumber.style.minWidth = (originalLineNumbersWidth + 'px');
originalLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;
if (originalLine !== 0) {
originalLineNumber.appendChild(document.createTextNode(String(originalLine)));
} else {
originalLineNumber.innerHTML = '&nbsp;';
}
cell.appendChild(originalLineNumber);
const modifiedLineNumber = document.createElement('span');
modifiedLineNumber.style.width = (modifiedLineNumbersWidth + 'px');
modifiedLineNumber.style.minWidth = (modifiedLineNumbersWidth + 'px');
modifiedLineNumber.style.paddingRight = '10px';
modifiedLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;
if (modifiedLine !== 0) {
modifiedLineNumber.appendChild(document.createTextNode(String(modifiedLine)));
} else {
modifiedLineNumber.innerHTML = '&nbsp;';
}
cell.appendChild(modifiedLineNumber);
const spacer = document.createElement('span');
spacer.className = spacerClassName;
spacer.innerHTML = '&nbsp;&nbsp;';
cell.appendChild(spacer);
let lineContent: string;
if (modifiedLine !== 0) {
cell.insertAdjacentHTML('beforeend',
this._renderLine(modifiedModel, modifiedOpts, modifiedModelOpts.tabSize, modifiedLine)
);
lineContent = modifiedModel.getLineContent(modifiedLine);
} else {
cell.insertAdjacentHTML('beforeend',
this._renderLine(originalModel, originalOpts, originalModelOpts.tabSize, originalLine)
);
lineContent = originalModel.getLineContent(originalLine);
}
if (lineContent.length === 0) {
lineContent = nls.localize('blankLine', "blank");
}
let ariaLabel: string;
switch (type) {
case DiffEntryType.Equal:
ariaLabel = nls.localize('equalLine', "original {0}, modified {1}: {2}", originalLine, modifiedLine, lineContent);
break;
case DiffEntryType.Insert:
ariaLabel = nls.localize('insertLine', "+ modified {0}: {1}", modifiedLine, lineContent);
break;
case DiffEntryType.Delete:
ariaLabel = nls.localize('deleteLine', "- original {0}: {1}", originalLine, lineContent);
break;
}
row.setAttribute('aria-label', ariaLabel);
dest.appendChild(row);
}
}
private static _renderLine(model: editorCommon.IModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number): string {
const lineContent = model.getLineContent(lineNumber);
const defaultMetadata = (
(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)
| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
const r = renderViewLine(new RenderLineInput(
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
lineContent,
model.mightContainRTL(),
0,
[new ViewLineToken(lineContent.length, defaultMetadata)],
[],
tabSize,
config.fontInfo.spaceWidth,
config.viewInfo.stopRenderingLineAfter,
config.viewInfo.renderWhitespace,
config.viewInfo.renderControlCharacters,
config.viewInfo.fontLigatures
));
return r.html;
}
}
// theming
registerThemingParticipant((theme, collector) => {
let lineNumbers = theme.getColor(editorLineNumbers);
if (lineNumbers) {
collector.addRule(`.monaco-diff-editor .diff-review-line-number { color: ${lineNumbers}; }`);
}
const shadow = theme.getColor(scrollbarShadow);
if (shadow) {
collector.addRule(`.monaco-diff-editor .diff-review-shadow { box-shadow: ${shadow} 0 -6px 6px -6px inset; }`);
}
});
@editorAction
class DiffReviewNext extends EditorAction {
constructor() {
super({
id: 'editor.action.diffReview.next',
label: nls.localize('editor.action.diffReview.next', "Go to Next Difference"),
alias: 'Go to Next Difference',
precondition: ContextKeyExpr.has('isInDiffEditor'),
kbOpts: {
kbExpr: null,
primary: KeyCode.F7
}
});
}
public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
const diffEditor = findFocusedDiffEditor(accessor);
if (diffEditor) {
diffEditor.diffReviewNext();
}
}
}
@editorAction
class DiffReviewPrev extends EditorAction {
constructor() {
super({
id: 'editor.action.diffReview.prev',
label: nls.localize('editor.action.diffReview.prev', "Go to Previous Difference"),
alias: 'Go to Previous Difference',
precondition: ContextKeyExpr.has('isInDiffEditor'),
kbOpts: {
kbExpr: null,
primary: KeyMod.Shift | KeyCode.F7
}
});
}
public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
const diffEditor = findFocusedDiffEditor(accessor);
if (diffEditor) {
diffEditor.diffReviewPrev();
}
}
}
function findFocusedDiffEditor(accessor: ServicesAccessor): DiffEditorWidget {
const codeEditorService = accessor.get(ICodeEditorService);
const diffEditors = codeEditorService.listDiffEditors();
for (let i = 0, len = diffEditors.length; i < len; i++) {
const diffEditor = <DiffEditorWidget>diffEditors[i];
if (diffEditor.hasWidgetFocus()) {
return diffEditor;
}
}
return null;
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as objects from 'vs/base/common/objects';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
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 { IThemeService } from 'vs/platform/theme/common/themeService';
export class EmbeddedCodeEditorWidget extends CodeEditor {
private _parentEditor: ICodeEditor;
private _overwriteOptions: IEditorOptions;
constructor(
domElement: HTMLElement,
options: IEditorOptions,
parentEditor: ICodeEditor,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@ICommandService commandService: ICommandService,
@IContextKeyService contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService
) {
super(domElement, parentEditor.getRawConfiguration(), instantiationService, codeEditorService, commandService, contextKeyService, themeService);
this._parentEditor = parentEditor;
this._overwriteOptions = options;
// Overwrite parent's options
super.updateOptions(this._overwriteOptions);
this._register(parentEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => this._onParentConfigurationChanged(e)));
}
public getParentEditor(): ICodeEditor {
return this._parentEditor;
}
private _onParentConfigurationChanged(e: IConfigurationChangedEvent): void {
super.updateOptions(this._parentEditor.getRawConfiguration());
super.updateOptions(this._overwriteOptions);
}
public updateOptions(newOptions: IEditorOptions): void {
objects.mixin(this._overwriteOptions, newOptions, true);
super.updateOptions(this._overwriteOptions);
}
}

View File

@@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#C5C5C5"/><rect height="3" width="11" y="7" x="3" fill="#C5C5C5"/></svg>

After

Width:  |  Height:  |  Size: 203 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#424242"/><rect height="3" width="11" y="7" x="3" fill="#424242"/></svg>

After

Width:  |  Height:  |  Size: 203 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#e8e8e8" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#424242" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="3" width="11" y="7" x="3" fill="#C5C5C5"/></svg>

After

Width:  |  Height:  |  Size: 147 B

View File

@@ -0,0 +1 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="3" width="11" y="7" x="3" fill="#424242"/></svg>

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

View File

@@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* ---------- DiffEditor ---------- */
.monaco-diff-editor .diffOverview {
z-index: 9;
}
/* colors not externalized: using transparancy on background */
.monaco-diff-editor.vs .diffOverview { background: rgba(0, 0, 0, 0.03); }
.monaco-diff-editor.vs-dark .diffOverview { background: rgba(255, 255, 255, 0.01); }
.monaco-diff-editor .diffViewport {
box-shadow: inset 0px 0px 1px 0px #B9B9B9;
background: rgba(0, 0, 0, 0.10);
}
.monaco-diff-editor.vs-dark .diffViewport,
.monaco-diff-editor.hc-black .diffViewport {
background: rgba(255, 255, 255, 0.10);
}
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar { background: rgba(0,0,0,0); }
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar { background: rgba(0,0,0,0); }
.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar { background: none; }
.monaco-scrollable-element.modified-in-monaco-diff-editor .slider {
z-index: 10;
}
.modified-in-monaco-diff-editor .slider.active { background: rgba(171, 171, 171, .4); }
.modified-in-monaco-diff-editor.hc-black .slider.active { background: none; }
/* ---------- Diff ---------- */
.monaco-editor .insert-sign,
.monaco-diff-editor .insert-sign,
.monaco-editor .delete-sign,
.monaco-diff-editor .delete-sign {
background-size: 60%;
opacity: 0.7;
background-repeat: no-repeat;
background-position: 50% 50%;
}
.monaco-editor.hc-black .insert-sign,
.monaco-diff-editor.hc-black .insert-sign,
.monaco-editor.hc-black .delete-sign,
.monaco-diff-editor.hc-black .delete-sign {
opacity: 1;
}
.monaco-editor .insert-sign,
.monaco-diff-editor .insert-sign {
background-image: url('addition.svg');
}
.monaco-editor .delete-sign,
.monaco-diff-editor .delete-sign {
background-image: url('deletion.svg');
}
.monaco-editor.vs-dark .insert-sign,
.monaco-diff-editor.vs-dark .insert-sign,
.monaco-editor.hc-black .insert-sign,
.monaco-diff-editor.hc-black .insert-sign {
background-image: url('addition-inverse.svg');
}
.monaco-editor.vs-dark .delete-sign,
.monaco-diff-editor.vs-dark .delete-sign,
.monaco-editor.hc-black .delete-sign,
.monaco-diff-editor.hc-black .delete-sign {
background-image: url('deletion-inverse.svg');
}
.monaco-editor .inline-deleted-margin-view-zone {
text-align: right;
}
.monaco-editor .inline-added-margin-view-zone {
text-align: right;
}
.monaco-editor .diagonal-fill {
background: url('diagonal-fill.png');
}
.monaco-editor.vs-dark .diagonal-fill {
opacity: 0.2;
}
.monaco-editor.hc-black .diagonal-fill {
background: none;
}
/* ---------- Inline Diff ---------- */
.monaco-editor .view-zones .view-lines .view-line span {
display: inline-block;
}

View File

@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-diff-editor .diff-review-line-number {
text-align: right;
display: inline-block;
}
.monaco-diff-editor .diff-review {
position: absolute;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
}
.monaco-diff-editor .diff-review-summary {
padding-left: 10px;
}
.monaco-diff-editor .diff-review-shadow {
position: absolute;
}
.monaco-diff-editor .diff-review-row {
white-space: pre;
}
.monaco-diff-editor .diff-review-table {
display: table;
min-width: 100%;
}
.monaco-diff-editor .diff-review-row {
display: table-row;
width: 100%;
}
.monaco-diff-editor .diff-review-cell {
display: table-cell;
}
.monaco-diff-editor .diff-review-spacer {
display: inline-block;
width: 10px;
}
.monaco-diff-editor .diff-review-actions {
display: inline-block;
position: absolute;
right: 10px;
top: 2px;
}
.monaco-diff-editor .diff-review-actions .action-label {
width: 16px;
height: 16px;
margin: 2px 0;
}
.monaco-diff-editor .action-label.icon.close-diff-review {
background: url('close.svg') center center no-repeat;
}
.monaco-diff-editor.hc-black .action-label.icon.close-diff-review,
.monaco-diff-editor.vs-dark .action-label.icon.close-diff-review {
background: url('close-inverse.svg') center center no-repeat;
}

View File

@@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* -------------------- IE10 remove auto clear button -------------------- */
::-ms-clear {
display: none;
}
/* All widgets */
/* I am not a big fan of this rule */
.monaco-editor .editor-widget input {
color: inherit;
}
/* -------------------- Editor -------------------- */
.monaco-editor {
position: relative;
overflow: visible;
-webkit-text-size-adjust: 100%;
-webkit-font-feature-settings: "liga" off, "calt" off;
font-feature-settings: "liga" off, "calt" off;
}
.monaco-editor.enable-ligatures {
-webkit-font-feature-settings: "liga" on, "calt" on;
font-feature-settings: "liga" on, "calt" on;
}
/* -------------------- Misc -------------------- */
.monaco-editor .overflow-guard {
position: relative;
overflow: hidden;
}
.monaco-editor .view-overlays {
position: absolute;
top: 0;
}

View File

@@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .vs-whitespace {
display:inline-block;
}