Merge VS Code 1.21 source code (#1067)

* Initial VS Code 1.21 file copy with patches

* A few more merges

* Post npm install

* Fix batch of build breaks

* Fix more build breaks

* Fix more build errors

* Fix more build breaks

* Runtime fixes 1

* Get connection dialog working with some todos

* Fix a few packaging issues

* Copy several node_modules to package build to fix loader issues

* Fix breaks from master

* A few more fixes

* Make tests pass

* First pass of license header updates

* Second pass of license header updates

* Fix restore dialog issues

* Remove add additional themes menu items

* fix select box issues where the list doesn't show up

* formatting

* Fix editor dispose issue

* Copy over node modules to correct location on all platforms
This commit is contained in:
Karl Burtram
2018-04-04 15:27:51 -07:00
committed by GitHub
parent 5fba3e31b4
commit dafb780987
9412 changed files with 141255 additions and 98813 deletions

View File

@@ -335,6 +335,8 @@ export class Configuration extends CommonEditorConfiguration {
extra += 'ff ';
} else if (browser.isEdge) {
extra += 'edge ';
} else if (browser.isSafari) {
extra += 'safari ';
}
if (platform.isMacintosh) {
extra += 'mac ';

View File

@@ -455,10 +455,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.move(cursors.context, cursors.getAll(), args)
)
CursorMoveCommands.move(cursors.context, cursors.getAll(), args)
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -707,7 +704,7 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly || context.model.hasEditableRange()) {
if (context.config.readOnly) {
return;
}
@@ -772,7 +769,7 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly || context.model.hasEditableRange()) {
if (context.config.readOnly) {
return;
}
@@ -804,10 +801,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.moveToBeginningOfLine(cursors.context, cursors.getAll(), this._inSelectionMode)
)
CursorMoveCommands.moveToBeginningOfLine(cursors.context, cursors.getAll(), this._inSelectionMode)
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -856,10 +850,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
this._exec(cursors.context, cursors.getAll())
)
this._exec(cursors.context, cursors.getAll())
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -889,10 +880,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.moveToEndOfLine(cursors.context, cursors.getAll(), this._inSelectionMode)
)
CursorMoveCommands.moveToEndOfLine(cursors.context, cursors.getAll(), this._inSelectionMode)
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -941,10 +929,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
this._exec(cursors.context, cursors.getAll())
)
this._exec(cursors.context, cursors.getAll())
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -975,10 +960,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.moveToBeginningOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode)
)
CursorMoveCommands.moveToBeginningOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode)
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -1022,10 +1004,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.moveToEndOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode)
)
CursorMoveCommands.moveToEndOfBuffer(cursors.context, cursors.getAll(), this._inSelectionMode)
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -1272,7 +1251,7 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly || context.model.hasEditableRange()) {
if (context.config.readOnly) {
return;
}
@@ -1335,7 +1314,7 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly || context.model.hasEditableRange()) {
if (context.config.readOnly) {
return;
}
@@ -1383,10 +1362,7 @@ export namespace CoreNavigationCommands {
cursors.setStates(
args.source,
CursorChangeReason.Explicit,
CursorState.ensureInEditableRange(
cursors.context,
CursorMoveCommands.expandLineSelection(cursors.context, cursors.getAll())
)
CursorMoveCommands.expandLineSelection(cursors.context, cursors.getAll())
);
cursors.reveal(true, RevealTarget.Primary, editorCommon.ScrollType.Smooth);
}
@@ -1723,44 +1699,6 @@ class EditorOrNativeTextInputCommand extends Command {
}
}
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: CoreNavigationCommands.SelectAll,
inputHandler: 'selectAll',
id: 'editor.action.selectAll',
precondition: null,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: null,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
}
}));
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: H.Undo,
inputHandler: 'undo',
id: H.Undo,
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
}
}));
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: H.Redo,
inputHandler: 'redo',
id: H.Redo,
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
}
}));
/**
* A command that will invoke a command on the focused editor.
*/
@@ -1786,6 +1724,46 @@ class EditorHandlerCommand extends Command {
}
}
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: CoreNavigationCommands.SelectAll,
inputHandler: 'selectAll',
id: 'editor.action.selectAll',
precondition: null,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: null,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
}
}));
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: H.Undo,
inputHandler: 'undo',
id: H.Undo,
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
}
}));
registerCommand(new EditorHandlerCommand('default:' + H.Undo, H.Undo));
registerCommand(new EditorOrNativeTextInputCommand({
editorHandler: H.Redo,
inputHandler: 'redo',
id: H.Redo,
precondition: EditorContextKeys.writable,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textFocus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
}
}));
registerCommand(new EditorHandlerCommand('default:' + H.Redo, H.Redo));
function registerOverwritableCommand(handlerId: string): void {
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
registerCommand(new EditorHandlerCommand(handlerId, handlerId));

View File

@@ -364,7 +364,7 @@ abstract class BareHitTestRequest {
this.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + pos.y - editorPos.y);
this.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + pos.x - editorPos.x - ctx.layoutInfo.contentLeft;
this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft);
this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft && pos.x - editorPos.x >= ctx.layoutInfo.glyphMarginLeft);
this.isInContentArea = !this.isInMarginArea;
this.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth));
}
@@ -587,6 +587,8 @@ export class MouseTargetFactory {
offsetX: offset
};
offset -= ctx.layoutInfo.glyphMarginLeft;
if (offset <= ctx.layoutInfo.glyphMarginWidth) {
// On the glyph margin
return request.fulfill(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail);
@@ -694,7 +696,7 @@ export class MouseTargetFactory {
return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, void 0, EMPTY_CONTENT_IN_LINES);
}
let visibleRange = ctx.visibleRangeForPosition2(lineNumber, column);
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column);
if (!visibleRange) {
return request.fulfill(MouseTargetType.UNKNOWN, pos);
@@ -706,33 +708,35 @@ export class MouseTargetFactory {
return request.fulfill(MouseTargetType.CONTENT_TEXT, pos);
}
let mouseIsBetween: boolean;
// Let's define a, b, c and check if the offset is in between them...
interface OffsetColumn { offset: number; column: number; }
let points: OffsetColumn[] = [];
points.push({ offset: visibleRange.left, column: column });
if (column > 1) {
let prevColumnHorizontalOffset = visibleRange.left;
mouseIsBetween = false;
mouseIsBetween = mouseIsBetween || (prevColumnHorizontalOffset < request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset < columnHorizontalOffset); // LTR case
mouseIsBetween = mouseIsBetween || (columnHorizontalOffset < request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset < prevColumnHorizontalOffset); // RTL case
if (mouseIsBetween) {
let rng = new EditorRange(lineNumber, column, lineNumber, column - 1);
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column - 1);
if (visibleRange) {
points.push({ offset: visibleRange.left, column: column - 1 });
}
}
const lineMaxColumn = ctx.model.getLineMaxColumn(lineNumber);
if (column < lineMaxColumn) {
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column + 1);
if (visibleRange) {
points.push({ offset: visibleRange.left, column: column + 1 });
}
}
points.sort((a, b) => a.offset - b.offset);
for (let i = 1; i < points.length; i++) {
const prev = points[i - 1];
const curr = points[i];
if (prev.offset <= request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset <= curr.offset) {
const rng = new EditorRange(lineNumber, prev.column, lineNumber, curr.column);
return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, rng);
}
}
let lineMaxColumn = ctx.model.getLineMaxColumn(lineNumber);
if (column < lineMaxColumn) {
let nextColumnVisibleRange = ctx.visibleRangeForPosition2(lineNumber, column + 1);
if (nextColumnVisibleRange) {
let nextColumnHorizontalOffset = nextColumnVisibleRange.left;
mouseIsBetween = false;
mouseIsBetween = mouseIsBetween || (columnHorizontalOffset < request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset < nextColumnHorizontalOffset); // LTR case
mouseIsBetween = mouseIsBetween || (nextColumnHorizontalOffset < request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset < columnHorizontalOffset); // RTL case
if (mouseIsBetween) {
let rng = new EditorRange(lineNumber, column, lineNumber, column + 1);
return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, rng);
}
}
}
return request.fulfill(MouseTargetType.CONTENT_TEXT, pos);
}
@@ -940,4 +944,4 @@ export class MouseTargetFactory {
hitTarget: null
};
}
}
}

View File

@@ -19,13 +19,14 @@ import { HorizontalRange, RenderingContext, RestrictedRenderingContext } from 'v
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { ViewController } from 'vs/editor/browser/view/viewController';
import { EndOfLinePreference, ScrollType } from 'vs/editor/common/editorCommon';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { PartFingerprints, PartFingerprint, ViewPart } from 'vs/editor/browser/view/viewPart';
import { Margin } from 'vs/editor/browser/viewParts/margin/margin';
import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { EndOfLinePreference } from 'vs/editor/common/model';
export interface ITextAreaHandlerHelper {
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange;
@@ -51,6 +52,40 @@ class VisibleTextAreaData {
const canUseZeroSizeTextarea = (browser.isEdgeOrIE || browser.isFirefox);
interface LocalClipboardMetadata {
lastCopiedValue: string;
isFromEmptySelection: boolean;
multicursorText: string[];
}
/**
* Every time we write to the clipboard, we record a bit of extra metadata here.
* Every time we read from the cipboard, if the text matches our last written text,
* we can fetch the previous metadata.
*/
class LocalClipboardMetadataManager {
public static INSTANCE = new LocalClipboardMetadataManager();
private _lastState: LocalClipboardMetadata;
constructor() {
this._lastState = null;
}
public set(state: LocalClipboardMetadata): void {
this._lastState = state;
}
public get(pastedText: string): LocalClipboardMetadata {
if (this._lastState && this._lastState.lastCopiedValue === pastedText) {
// match!
return this._lastState;
}
this._lastState = null;
return null;
}
}
export class TextAreaHandler extends ViewPart {
private readonly _viewController: ViewController;
@@ -70,8 +105,6 @@ export class TextAreaHandler extends ViewPart {
*/
private _visibleTextArea: VisibleTextAreaData;
private _selections: Selection[];
private _lastCopiedValue: string;
private _lastCopiedValueIsFromEmptySelection: boolean;
public readonly textArea: FastDomNode<HTMLTextAreaElement>;
public readonly textAreaCover: FastDomNode<HTMLElement>;
@@ -97,8 +130,6 @@ export class TextAreaHandler extends ViewPart {
this._visibleTextArea = null;
this._selections = [new Selection(1, 1, 1, 1)];
this._lastCopiedValue = null;
this._lastCopiedValueIsFromEmptySelection = false;
// Text Area (The focus will always be in the textarea when the cursor is blinking)
this.textArea = createFastDomNode(document.createElement('textarea'));
@@ -132,21 +163,29 @@ export class TextAreaHandler extends ViewPart {
const textAreaInputHost: ITextAreaInputHost = {
getPlainTextToCopy: (): string => {
const whatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard);
const rawWhatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard);
const newLineCharacter = this._context.model.getEOL();
if (this._emptySelectionClipboard) {
if (browser.isFirefox) {
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
this._lastCopiedValue = whatToCopy.replace(/\r\n/g, '\n');
} else {
this._lastCopiedValue = whatToCopy;
}
const isFromEmptySelection = (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty());
const multicursorText = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy : null);
const whatToCopy = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy.join(newLineCharacter) : rawWhatToCopy);
let selections = this._selections;
this._lastCopiedValueIsFromEmptySelection = (selections.length === 1 && selections[0].isEmpty());
let metadata: LocalClipboardMetadata = null;
if (isFromEmptySelection || multicursorText) {
// Only store the non-default metadata
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
const lastCopiedValue = (browser.isFirefox ? whatToCopy.replace(/\r\n/g, '\n') : whatToCopy);
metadata = {
lastCopiedValue: lastCopiedValue,
isFromEmptySelection: (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty()),
multicursorText: multicursorText
};
}
LocalClipboardMetadataManager.INSTANCE.set(metadata);
return whatToCopy;
},
@@ -199,11 +238,15 @@ export class TextAreaHandler extends ViewPart {
}));
this._register(this._textAreaInput.onPaste((e: IPasteData) => {
const metadata = LocalClipboardMetadataManager.INSTANCE.get(e.text);
let pasteOnNewLine = false;
if (this._emptySelectionClipboard) {
pasteOnNewLine = (e.text === this._lastCopiedValue && this._lastCopiedValueIsFromEmptySelection);
let multicursorText: string[] = null;
if (metadata) {
pasteOnNewLine = (this._emptySelectionClipboard && metadata.isFromEmptySelection);
multicursorText = metadata.multicursorText;
}
this._viewController.paste('keyboard', e.text, pasteOnNewLine);
this._viewController.paste('keyboard', e.text, pasteOnNewLine, multicursorText);
}));
this._register(this._textAreaInput.onCut(() => {

View File

@@ -558,6 +558,10 @@ class TextAreaWrapper extends Disposable implements ITextAreaWrapper {
if (currentIsFocused && currentSelectionStart === selectionStart && currentSelectionEnd === selectionEnd) {
// No change
// Firefox iframe bug https://github.com/Microsoft/monaco-editor/issues/643#issuecomment-367871377
if (browser.isFirefox && window.parent !== window) {
textArea.focus();
}
return;
}
@@ -567,6 +571,9 @@ class TextAreaWrapper extends Disposable implements ITextAreaWrapper {
// No need to focus, only need to change the selection range
this.setIgnoreSelectionChangeTime('setSelectionRange');
textArea.setSelectionRange(selectionStart, selectionEnd);
if (browser.isFirefox && window.parent !== window) {
textArea.focus();
}
return;
}

View File

@@ -6,7 +6,7 @@
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
import { EndOfLinePreference } from 'vs/editor/common/model';
import * as strings from 'vs/base/common/strings';
export interface ITextAreaWrapper {

View File

@@ -30,7 +30,7 @@ export class EditorState {
this.flags = flags;
if ((this.flags & CodeEditorStateFlag.Value) !== 0) {
var model = editor.getModel();
let model = editor.getModel();
this.modelVersionId = model ? strings.format('{0}#{1}', model.uri.toString(), model.getVersionId()) : null;
}
if ((this.flags & CodeEditorStateFlag.Position) !== 0) {
@@ -50,7 +50,7 @@ export class EditorState {
if (!(other instanceof EditorState)) {
return false;
}
var state = <EditorState>other;
let state = <EditorState>other;
if (this.modelVersionId !== state.modelVersionId) {
return false;

View File

@@ -18,6 +18,7 @@ import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/ed
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ICursors, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer';
import { ITextModel, IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration } from 'vs/editor/common/model';
/**
* A view zone is a full horizontal rectangle that 'pushes' text down.
@@ -480,7 +481,7 @@ export interface ICodeEditor extends editorCommon.IEditor {
/**
* Type the getModel() of IEditor.
*/
getModel(): editorCommon.IModel;
getModel(): ITextModel;
/**
* Returns the current editor's configuration
@@ -495,13 +496,13 @@ export interface ICodeEditor extends editorCommon.IEditor {
/**
* Get value of the current model attached to this editor.
* @see IModel.getValue
* @see `ITextModel.getValue`
*/
getValue(options?: { preserveBOM: boolean; lineEnding: string; }): string;
/**
* Set the value of the current model attached to this editor.
* @see IModel.setValue
* @see `ITextModel.setValue`
*/
setValue(newValue: string): void;
@@ -563,7 +564,7 @@ export interface ICodeEditor extends editorCommon.IEditor {
* @param edits The edits to execute.
* @param endCursoState Cursor state after the edits were applied.
*/
executeEdits(source: string, edits: editorCommon.IIdentifiedSingleEditOperation[], endCursoState?: Selection[]): boolean;
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursoState?: Selection[]): boolean;
/**
* Execute multiple (concommitent) commands on the editor.
@@ -585,13 +586,13 @@ export interface ICodeEditor extends editorCommon.IEditor {
/**
* Get all the decorations on a line (filtering out decorations from other editors).
*/
getLineDecorations(lineNumber: number): editorCommon.IModelDecoration[];
getLineDecorations(lineNumber: number): IModelDecoration[];
/**
* All decorations added through this call will get the ownerId of this editor.
* @see IModel.deltaDecorations
* @see `ITextModel.deltaDecorations`
*/
deltaDecorations(oldDecorations: string[], newDecorations: editorCommon.IModelDeltaDecoration[]): string[];
deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];
/**
* @internal
@@ -618,6 +619,12 @@ export interface ICodeEditor extends editorCommon.IEditor {
*/
getCenteredRangeInViewport(): Range;
/**
* Returns the ranges that are currently visible.
* Does not account for horizontal scrolling.
*/
getVisibleRanges(): Range[];
/**
* Get the view zones.
* @internal

View File

@@ -20,6 +20,7 @@ import { IEditorService } from 'vs/platform/editor/common/editor';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditorService, getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ITextModel } from 'vs/editor/common/model';
export type ServicesAccessor = ServicesAccessor;
export type IEditorContributionCtor = IConstructorSignature1<ICodeEditor, editorCommon.IEditorContribution>;
@@ -30,14 +31,12 @@ export interface ICommandKeybindingsOptions extends IKeybindings {
kbExpr?: ContextKeyExpr;
weight?: number;
}
export interface ICommandOptions {
id: string;
precondition: ContextKeyExpr;
kbOpts?: ICommandKeybindingsOptions;
description?: ICommandHandlerDescription;
}
export abstract class Command {
public readonly id: string;
public readonly precondition: ContextKeyExpr;
@@ -224,7 +223,7 @@ export function registerLanguageCommand(id: string, handler: (accessor: Services
CommandsRegistry.registerCommand(id, (accessor, args) => handler(accessor, args || {}));
}
export function registerDefaultLanguageCommand(id: string, handler: (model: editorCommon.IModel, position: Position, args: { [n: string]: any }) => any) {
export function registerDefaultLanguageCommand(id: string, handler: (model: ITextModel, position: Position, args: { [n: string]: any }) => any) {
registerLanguageCommand(id, function (accessor, args) {
const { resource, position } = args;

View File

@@ -5,7 +5,8 @@
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
import { IDecorationRenderOptions, IModelDecorationOptions, IModel } from 'vs/editor/common/editorCommon';
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
@@ -102,7 +103,7 @@ export abstract class AbstractCodeEditorService implements ICodeEditorService {
private _transientWatchers: { [uri: string]: ModelTransientSettingWatcher; } = {};
public setTransientModelProperty(model: IModel, key: string, value: any): void {
public setTransientModelProperty(model: ITextModel, key: string, value: any): void {
const uri = model.uri.toString();
let w: ModelTransientSettingWatcher;
@@ -116,7 +117,7 @@ export abstract class AbstractCodeEditorService implements ICodeEditorService {
w.set(key, value);
}
public getTransientModelProperty(model: IModel, key: string): any {
public getTransientModelProperty(model: ITextModel, key: string): any {
const uri = model.uri.toString();
if (!this._transientWatchers.hasOwnProperty(uri)) {
@@ -135,7 +136,7 @@ export class ModelTransientSettingWatcher {
public readonly uri: string;
private readonly _values: { [key: string]: any; };
constructor(uri: string, model: IModel, owner: AbstractCodeEditorService) {
constructor(uri: string, model: ITextModel, owner: AbstractCodeEditorService) {
this.uri = uri;
this._values = {};
model.onWillDispose(() => owner._removeWatcher(this));

View File

@@ -5,75 +5,55 @@
'use strict';
import * as nls from 'vs/nls';
import { flatten } from 'vs/base/common/arrays';
import { IStringDictionary, forEach, values, groupBy, size } from 'vs/base/common/collections';
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IFileService, IFileChange } from 'vs/platform/files/common/files';
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
import { IIdentifiedSingleEditOperation, IModel, EndOfLineSequence } from 'vs/editor/common/editorCommon';
import { IProgressRunner } from 'vs/platform/progress/common/progress';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IIdentifiedSingleEditOperation, ITextModel, EndOfLineSequence } from 'vs/editor/common/model';
import { IProgressRunner, emptyProgressRunner, IProgress } from 'vs/platform/progress/common/progress';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { ResourceTextEdit, ResourceFileEdit, isResourceFileEdit, isResourceTextEdit } from 'vs/editor/common/modes';
import { getPathLabel } from 'vs/base/common/labels';
export interface IResourceEdit {
resource: URI;
range?: IRange;
newText: string;
newEol?: EndOfLineSequence;
}
interface IRecording {
stop(): void;
hasChanged(resource: URI): boolean;
allChanges(): IFileChange[];
}
abstract class IRecording {
class ChangeRecorder {
private _fileService: IFileService;
constructor(fileService?: IFileService) {
this._fileService = fileService;
}
public start(): IRecording {
const changes: IStringDictionary<IFileChange[]> = Object.create(null);
static start(fileService: IFileService): IRecording {
const _changes = new Set<string>();
let stop: IDisposable;
if (this._fileService) {
stop = this._fileService.onFileChanges((event) => {
event.changes.forEach(change => {
const key = String(change.resource);
let array = changes[key];
if (!array) {
changes[key] = array = [];
if (fileService) {
// watch only when there is a fileservice available
stop = fileService.onFileChanges(event => {
for (const change of event.changes) {
if (change.type === FileChangeType.UPDATED) {
_changes.add(change.resource.toString());
}
array.push(change);
});
}
});
}
return {
stop: () => { return stop && stop.dispose(); },
hasChanged: (resource: URI) => !!changes[resource.toString()],
allChanges: () => flatten(values(changes))
stop() { return dispose(stop); },
hasChanged(resource) { return _changes.has(resource.toString()); }
};
}
abstract stop(): void;
abstract hasChanged(resource: URI): boolean;
}
class EditTask implements IDisposable {
private _initialSelections: Selection[];
private _endCursorSelection: Selection;
private get _model(): IModel { return this._modelReference.object.textEditorModel; }
private get _model(): ITextModel { return this._modelReference.object.textEditorModel; }
private _modelReference: IReference<ITextEditorModel>;
private _edits: IIdentifiedSingleEditOperation[];
private _newEol: EndOfLineSequence;
@@ -84,26 +64,34 @@ class EditTask implements IDisposable {
this._edits = [];
}
public addEdit(edit: IResourceEdit): void {
if (typeof edit.newEol === 'number') {
// honor eol-change
this._newEol = edit.newEol;
}
if (edit.range || edit.newText) {
// create edit operation
let range: Range;
if (!edit.range) {
range = this._model.getFullModelRange();
} else {
range = Range.lift(edit.range);
}
this._edits.push(EditOperation.replaceMove(range, edit.newText));
dispose() {
if (this._model) {
this._modelReference.dispose();
this._modelReference = null;
}
}
public apply(): void {
addEdit(resourceEdit: ResourceTextEdit): void {
for (const edit of resourceEdit.edits) {
if (typeof edit.eol === 'number') {
// honor eol-change
this._newEol = edit.eol;
}
if (edit.range || edit.text) {
// create edit operation
let range: Range;
if (!edit.range) {
range = this._model.getFullModelRange();
} else {
range = Range.lift(edit.range);
}
this._edits.push(EditOperation.replaceMove(range, edit.text));
}
}
}
apply(): void {
if (this._edits.length > 0) {
this._edits = this._edits.map((value, index) => ({ value, index })).sort((a, b) => {
@@ -160,16 +148,10 @@ class EditTask implements IDisposable {
return [this._endCursorSelection];
}
public getEndCursorSelection(): Selection {
getEndCursorSelection(): Selection {
return this._endCursorSelection;
}
dispose() {
if (this._model) {
this._modelReference.dispose();
this._modelReference = null;
}
}
}
class SourceModelEditTask extends EditTask {
@@ -189,34 +171,42 @@ class SourceModelEditTask extends EditTask {
class BulkEditModel implements IDisposable {
private _textModelResolverService: ITextModelService;
private _numberOfResourcesToModify: number = 0;
private _edits: IStringDictionary<IResourceEdit[]> = Object.create(null);
private _edits = new Map<string, ResourceTextEdit[]>();
private _tasks: EditTask[];
private _sourceModel: URI;
private _sourceSelections: Selection[];
private _sourceModelTask: SourceModelEditTask;
private _progress: IProgress<void>;
constructor(textModelResolverService: ITextModelService, sourceModel: URI, sourceSelections: Selection[], edits: IResourceEdit[], private progress: IProgressRunner = null) {
constructor(
textModelResolverService: ITextModelService,
editor: ICodeEditor,
edits: ResourceTextEdit[],
progress: IProgress<void>
) {
this._textModelResolverService = textModelResolverService;
this._sourceModel = sourceModel;
this._sourceSelections = sourceSelections;
this._sourceModelTask = null;
this._sourceModel = editor ? editor.getModel().uri : undefined;
this._sourceSelections = editor ? editor.getSelections() : undefined;
this._sourceModelTask = undefined;
this._progress = progress;
for (let edit of edits) {
this._addEdit(edit);
}
edits.forEach(this.addEdit, this);
}
private _addEdit(edit: IResourceEdit): void {
let array = this._edits[edit.resource.toString()];
dispose(): void {
this._tasks = dispose(this._tasks);
}
addEdit(edit: ResourceTextEdit): void {
let array = this._edits.get(edit.resource.toString());
if (!array) {
this._edits[edit.resource.toString()] = array = [];
this._numberOfResourcesToModify += 1;
array = [];
this._edits.set(edit.resource.toString(), array);
}
array.push(edit);
}
public prepare(): TPromise<BulkEditModel> {
async prepare(): TPromise<BulkEditModel> {
if (this._tasks) {
throw new Error('illegal state - already prepared');
@@ -225,145 +215,80 @@ class BulkEditModel implements IDisposable {
this._tasks = [];
const promises: TPromise<any>[] = [];
if (this.progress) {
this.progress.total(this._numberOfResourcesToModify * 2);
}
forEach(this._edits, entry => {
const promise = this._textModelResolverService.createModelReference(URI.parse(entry.key)).then(ref => {
this._edits.forEach((value, key) => {
const promise = this._textModelResolverService.createModelReference(URI.parse(key)).then(ref => {
const model = ref.object;
if (!model || !model.textEditorModel) {
throw new Error(`Cannot load file ${entry.key}`);
throw new Error(`Cannot load file ${key}`);
}
const textEditorModel = model.textEditorModel;
let task: EditTask;
if (this._sourceModel && textEditorModel.uri.toString() === this._sourceModel.toString()) {
if (this._sourceModel && model.textEditorModel.uri.toString() === this._sourceModel.toString()) {
this._sourceModelTask = new SourceModelEditTask(ref, this._sourceSelections);
task = this._sourceModelTask;
} else {
task = new EditTask(ref);
}
entry.value.forEach(edit => task.addEdit(edit));
value.forEach(edit => task.addEdit(edit));
this._tasks.push(task);
if (this.progress) {
this.progress.worked(1);
}
this._progress.report(undefined);
});
promises.push(promise);
});
await TPromise.join(promises);
return TPromise.join(promises).then(_ => this);
return this;
}
public apply(): Selection {
this._tasks.forEach(task => this.applyTask(task));
let r: Selection = null;
if (this._sourceModelTask) {
r = this._sourceModelTask.getEndCursorSelection();
apply(): Selection {
for (const task of this._tasks) {
task.apply();
this._progress.report(undefined);
}
return r;
}
private applyTask(task: EditTask): void {
task.apply();
if (this.progress) {
this.progress.worked(1);
}
}
dispose(): void {
this._tasks = dispose(this._tasks);
return this._sourceModelTask
? this._sourceModelTask.getEndCursorSelection()
: undefined;
}
}
export interface BulkEdit {
progress(progress: IProgressRunner): void;
add(edit: IResourceEdit[]): void;
finish(): TPromise<ISelection>;
ariaMessage(): string;
}
export type Edit = ResourceFileEdit | ResourceTextEdit;
export function bulkEdit(textModelResolverService: ITextModelService, editor: ICodeEditor, edits: IResourceEdit[], fileService?: IFileService, progress: IProgressRunner = null): TPromise<any> {
let bulk = createBulkEdit(textModelResolverService, editor, fileService);
bulk.add(edits);
bulk.progress(progress);
return bulk.finish();
}
export class BulkEdit {
export function createBulkEdit(textModelResolverService: ITextModelService, editor?: ICodeEditor, fileService?: IFileService): BulkEdit {
let all: IResourceEdit[] = [];
let recording = new ChangeRecorder(fileService).start();
let progressRunner: IProgressRunner;
function progress(progress: IProgressRunner) {
progressRunner = progress;
static perform(edits: Edit[], textModelService: ITextModelService, fileService: IFileService, editor: ICodeEditor): TPromise<any> {
const edit = new BulkEdit(editor, null, textModelService, fileService);
edit.add(edits);
return edit.perform();
}
function add(edits: IResourceEdit[]): void {
all.push(...edits);
private _edits: Edit[] = [];
private _editor: ICodeEditor;
private _progress: IProgressRunner;
constructor(
editor: ICodeEditor,
progress: IProgressRunner,
@ITextModelService private readonly _textModelService: ITextModelService,
@optional(IFileService) private _fileService: IFileService
) {
this._editor = editor;
this._progress = progress || emptyProgressRunner;
}
function getConcurrentEdits() {
let names: string[];
for (let edit of all) {
if (recording.hasChanged(edit.resource)) {
if (!names) {
names = [];
}
names.push(edit.resource.fsPath);
}
add(edits: Edit[] | Edit): void {
if (Array.isArray(edits)) {
this._edits.push(...edits);
} else {
this._edits.push(edits);
}
if (names) {
return nls.localize('conflict', "These files have changed in the meantime: {0}", names.join(', '));
}
return undefined;
}
function finish(): TPromise<ISelection> {
if (all.length === 0) {
return TPromise.as(undefined);
}
let concurrentEdits = getConcurrentEdits();
if (concurrentEdits) {
return TPromise.wrapError<ISelection>(new Error(concurrentEdits));
}
let uri: URI;
let selections: Selection[];
if (editor && editor.getModel()) {
uri = editor.getModel().uri;
selections = editor.getSelections();
}
const model = new BulkEditModel(textModelResolverService, uri, selections, all, progressRunner);
return model.prepare().then(_ => {
let concurrentEdits = getConcurrentEdits();
if (concurrentEdits) {
throw new Error(concurrentEdits);
}
recording.stop();
const result = model.apply();
model.dispose();
return result;
});
}
function ariaMessage(): string {
let editCount = all.length;
let resourceCount = size(groupBy(all, edit => edit.resource.toString()));
ariaMessage(): string {
const editCount = this._edits.reduce((prev, cur) => isResourceFileEdit(cur) ? prev : prev + cur.edits.length, 0);
const resourceCount = this._edits.length;
if (editCount === 0) {
return nls.localize('summary.0', "Made no edits");
} else if (editCount > 1 && resourceCount > 1) {
@@ -373,10 +298,84 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
}
}
return {
progress,
add,
finish,
ariaMessage
};
async perform(): TPromise<Selection> {
let seen = new Set<string>();
let total = 0;
const groups: Edit[][] = [];
let group: Edit[];
for (const edit of this._edits) {
if (!group
|| (isResourceFileEdit(group[0]) && !isResourceFileEdit(edit))
|| (isResourceTextEdit(group[0]) && !isResourceTextEdit(edit))
) {
group = [];
groups.push(group);
}
group.push(edit);
if (isResourceFileEdit(edit)) {
total += 1;
} else if (!seen.has(edit.resource.toString())) {
seen.add(edit.resource.toString());
total += 2;
}
}
// define total work and progress callback
// for child operations
this._progress.total(total);
let progress: IProgress<void> = { report: _ => this._progress.worked(1) };
// do it. return the last selection computed
// by a text change (can be undefined then)
let res: Selection = undefined;
for (const group of groups) {
if (isResourceFileEdit(group[0])) {
await this._performFileEdits(<ResourceFileEdit[]>group, progress);
} else {
res = await this._performTextEdits(<ResourceTextEdit[]>group, progress) || res;
}
}
return res;
}
private async _performFileEdits(edits: ResourceFileEdit[], progress: IProgress<void>) {
for (const edit of edits) {
progress.report(undefined);
if (edit.newUri && edit.oldUri) {
await this._fileService.moveFile(edit.oldUri, edit.newUri, false);
} else if (!edit.newUri && edit.oldUri) {
await this._fileService.del(edit.oldUri, true);
} else if (edit.newUri && !edit.oldUri) {
await this._fileService.createFile(edit.newUri, undefined, { overwrite: false });
}
}
}
private async _performTextEdits(edits: ResourceTextEdit[], progress: IProgress<void>): TPromise<Selection> {
const recording = IRecording.start(this._fileService);
const model = new BulkEditModel(this._textModelService, this._editor, edits, progress);
await model.prepare();
const conflicts = edits
.filter(edit => recording.hasChanged(edit.resource))
.map(edit => getPathLabel(edit.resource));
recording.stop();
if (conflicts.length > 0) {
model.dispose();
throw new Error(nls.localize('conflict', "These files have changed in the meantime: {0}", conflicts.join(', ')));
}
const selection = await model.apply();
model.dispose();
return selection;
}
}

View File

@@ -6,7 +6,8 @@
import Event from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDecorationRenderOptions, IModelDecorationOptions, IModel } from 'vs/editor/common/editorCommon';
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model';
import { IEditor } from 'vs/platform/editor/common/editor';
import { ICodeEditor, IDiffEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
@@ -38,8 +39,8 @@ export interface ICodeEditorService {
removeDecorationType(key: string): void;
resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions;
setTransientModelProperty(model: IModel, key: string, value: any): void;
getTransientModelProperty(model: IModel, key: string): any;
setTransientModelProperty(model: ITextModel, key: string, value: any): void;
getTransientModelProperty(model: ITextModel, key: string): any;
}
/**

View File

@@ -7,10 +7,8 @@
import * as strings from 'vs/base/common/strings';
import URI from 'vs/base/common/uri';
import * as dom from 'vs/base/browser/dom';
import {
IDecorationRenderOptions, IModelDecorationOptions, IModelDecorationOverviewRulerOptions, IThemeDecorationRenderOptions,
IContentDecorationRenderOptions, OverviewRulerLane, TrackedRangeStickiness, isThemeColor
} from 'vs/editor/common/editorCommon';
import { IDecorationRenderOptions, IThemeDecorationRenderOptions, IContentDecorationRenderOptions, isThemeColor } from 'vs/editor/common/editorCommon';
import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
import { AbstractCodeEditorService } from 'vs/editor/browser/services/abstractCodeEditorService';
import { IDisposable, dispose as disposeAll } from 'vs/base/common/lifecycle';
import { IThemeService, ITheme, ThemeColor } from 'vs/platform/theme/common/themeService';
@@ -210,6 +208,8 @@ const _CSS_MAP = {
borderStyle: 'border-style:{0};',
borderWidth: 'border-width:{0};',
fontStyle: 'font-style:{0};',
fontWeight: 'font-weight:{0};',
textDecoration: 'text-decoration:{0};',
cursor: 'cursor:{0};',
letterSpacing: 'letter-spacing:{0};',
@@ -357,7 +357,7 @@ class DecorationCSSRules {
return '';
}
let cssTextArr: string[] = [];
this.collectCSSText(opts, ['textDecoration', 'cursor', 'color', 'letterSpacing'], cssTextArr);
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'cursor', 'color', 'letterSpacing'], cssTextArr);
return cssTextArr.join('');
}
@@ -372,10 +372,12 @@ class DecorationCSSRules {
if (typeof opts !== 'undefined') {
this.collectBorderSettingsCSSText(opts, cssTextArr);
if (typeof opts.contentIconPath === 'string') {
cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, URI.file(opts.contentIconPath).toString().replace(/'/g, '%27')));
} else if (opts.contentIconPath instanceof URI) {
cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, opts.contentIconPath.toString(true).replace(/'/g, '%27')));
if (typeof opts.contentIconPath !== 'undefined') {
if (typeof opts.contentIconPath === 'string') {
cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, URI.file(opts.contentIconPath).toString().replace(/'/g, '%27')));
} else {
cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, URI.revive(opts.contentIconPath).toString(true).replace(/'/g, '%27')));
}
}
if (typeof opts.contentText === 'string') {
const truncated = opts.contentText.match(/^.*$/m)[0]; // only take first line
@@ -383,7 +385,7 @@ class DecorationCSSRules {
cssTextArr.push(strings.format(_CSS_MAP.contentText, escaped));
}
this.collectCSSText(opts, ['textDecoration', 'color', 'backgroundColor', 'margin'], cssTextArr);
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'color', 'backgroundColor', 'margin'], cssTextArr);
if (this.collectCSSText(opts, ['width', 'height'], cssTextArr)) {
cssTextArr.push('display:inline-block;');
}
@@ -405,7 +407,7 @@ class DecorationCSSRules {
if (typeof opts.gutterIconPath === 'string') {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, URI.file(opts.gutterIconPath).toString()));
} else {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, opts.gutterIconPath.toString(true).replace(/'/g, '%27')));
cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, URI.revive(opts.gutterIconPath).toString(true).replace(/'/g, '%27')));
}
if (typeof opts.gutterIconSize !== 'undefined') {
cssTextArr.push(strings.format(_CSS_MAP.gutterIconSize, opts.gutterIconSize));

View File

@@ -62,10 +62,11 @@ export class ViewController {
this._execCoreEditorCommandFunc(editorCommand, args);
}
public paste(source: string, text: string, pasteOnNewLine: boolean): void {
public paste(source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]): void {
this.commandService.executeCommand(editorCommon.Handler.Paste, {
text: text,
pasteOnNewLine: pasteOnNewLine,
multicursorText: multicursorText
});
}

View File

@@ -450,6 +450,13 @@ export class View extends ViewEventHandler {
this._scrollbar.delegateVerticalScrollbarMouseDown(browserEvent);
}
public restoreState(scrollPosition: { scrollLeft: number; scrollTop: number; }): void {
this._context.viewLayout.setScrollPositionNow({ scrollTop: scrollPosition.scrollTop });
this._renderNow();
this.viewLines.updateLineWidths();
this._context.viewLayout.setScrollPositionNow({ scrollLeft: scrollPosition.scrollLeft });
}
public getOffsetForColumn(modelLineNumber: number, modelColumn: number): number {
let modelPosition = this._context.model.validateModelPosition({
lineNumber: modelLineNumber,
@@ -472,8 +479,8 @@ export class View extends ViewEventHandler {
return this.outgoingEvents;
}
public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): OverviewRuler {
return new OverviewRuler(this._context, cssClassName, minimumHeight, maximumHeight);
public createOverviewRuler(cssClassName: string): OverviewRuler {
return new OverviewRuler(this._context, cssClassName);
}
public change(callback: (changeAccessor: editorBrowser.IViewZoneChangeAccessor) => any): boolean {

View File

@@ -80,7 +80,7 @@ export class RenderedLinesCollection<T extends ILine> {
public getLine(lineNumber: number): T {
let lineIndex = lineNumber - this._rendLineNumberStart;
if (lineIndex < 0 || lineIndex >= this._lines.length) {
throw new Error('Illegal value for lineNumber: ' + lineNumber);
throw new Error('Illegal value for lineNumber');
}
return this._lines[lineIndex];
}

View File

@@ -18,7 +18,6 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
private _lineHeight: number;
private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all';
private _selectionIsEmpty: boolean;
private _primaryCursorIsInEditableRange: boolean;
private _primaryCursorLineNumber: number;
private _scrollWidth: number;
private _contentWidth: number;
@@ -30,7 +29,6 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
this._renderLineHighlight = this._context.configuration.editor.viewInfo.renderLineHighlight;
this._selectionIsEmpty = true;
this._primaryCursorIsInEditableRange = true;
this._primaryCursorLineNumber = 1;
this._scrollWidth = 0;
this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth;
@@ -61,11 +59,6 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
let hasChanged = false;
if (this._primaryCursorIsInEditableRange !== e.isInEditableRange) {
this._primaryCursorIsInEditableRange = e.isInEditableRange;
hasChanged = true;
}
const primaryCursorLineNumber = e.selections[0].positionLineNumber;
if (this._primaryCursorLineNumber !== primaryCursorLineNumber) {
this._primaryCursorLineNumber = primaryCursorLineNumber;
@@ -127,14 +120,12 @@ export class CurrentLineHighlightOverlay extends DynamicViewOverlay {
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

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .current-line-margin {
.monaco-editor .margin-view-overlays .current-line {
display: block;
position: absolute;
left: 0;
@@ -11,6 +11,6 @@
box-sizing: border-box;
}
.monaco-editor .margin-view-overlays .current-line-margin.current-line-margin-both {
.monaco-editor .margin-view-overlays .current-line.current-line-margin.current-line-margin-both {
border-right: 0;
}

View File

@@ -18,7 +18,6 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
private _lineHeight: number;
private _renderLineHighlight: 'none' | 'gutter' | 'line' | 'all';
private _selectionIsEmpty: boolean;
private _primaryCursorIsInEditableRange: boolean;
private _primaryCursorLineNumber: number;
private _contentLeft: number;
@@ -29,7 +28,6 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
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;
@@ -59,11 +57,6 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
let hasChanged = false;
if (this._primaryCursorIsInEditableRange !== e.isInEditableRange) {
this._primaryCursorIsInEditableRange = e.isInEditableRange;
hasChanged = true;
}
const primaryCursorLineNumber = e.selections[0].positionLineNumber;
if (this._primaryCursorLineNumber !== primaryCursorLineNumber) {
this._primaryCursorLineNumber = primaryCursorLineNumber;
@@ -98,21 +91,21 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
public render(startLineNumber: number, lineNumber: number): string {
if (lineNumber === this._primaryCursorLineNumber) {
let className = 'current-line';
if (this._shouldShowCurrentLine()) {
const paintedInContent = this._willRenderContentCurrentLine();
const className = 'current-line-margin' + (paintedInContent ? ' current-line-margin-both' : '');
return (
'<div class="'
+ className
+ '" style="width:'
+ String(this._contentLeft)
+ 'px; height:'
+ String(this._lineHeight)
+ 'px;"></div>'
);
} else {
return '';
className = 'current-line current-line-margin' + (paintedInContent ? ' current-line-margin-both' : '');
}
return (
'<div class="'
+ className
+ '" style="width:'
+ String(this._contentLeft)
+ 'px; height:'
+ String(this._lineHeight)
+ 'px;"></div>'
);
}
return '';
}
@@ -120,7 +113,6 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
private _shouldShowCurrentLine(): boolean {
return (
(this._renderLineHighlight === 'gutter' || this._renderLineHighlight === 'all')
&& this._primaryCursorIsInEditableRange
);
}
@@ -128,7 +120,6 @@ export class CurrentLineMarginHighlightOverlay extends DynamicViewOverlay {
return (
(this._renderLineHighlight === 'line' || this._renderLineHighlight === 'all')
&& this._selectionIsEmpty
&& this._primaryCursorIsInEditableRange
);
}
}

View File

@@ -202,7 +202,7 @@ export class DecorationsOverlay extends DynamicViewOverlay {
}
let lineIndex = lineNumber - startLineNumber;
if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
throw new Error('Unexpected render request');
return '';
}
return this._renderResult[lineIndex];
}

View File

@@ -99,7 +99,13 @@ export class EditorScrollbar extends ViewPart {
const layoutInfo = this._context.configuration.editor.layoutInfo;
this.scrollbarDomNode.setLeft(layoutInfo.contentLeft);
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth);
const side = this._context.configuration.editor.viewInfo.minimap.side;
if (side === 'right') {
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth);
} else {
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth);
}
this.scrollbarDomNode.setHeight(layoutInfo.contentHeight);
}

View File

@@ -193,8 +193,8 @@ export class GlyphMarginOverlay extends DedupOverlay {
}
let lineIndex = lineNumber - startLineNumber;
if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
throw new Error('Unexpected render request');
return '';
}
return this._renderResult[lineIndex];
}
}
}

View File

@@ -122,7 +122,7 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
}
let lineIndex = lineNumber - startLineNumber;
if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
throw new Error('Unexpected render request');
return '';
}
return this._renderResult[lineIndex];
}

View File

@@ -6,7 +6,7 @@
'use strict';
import 'vs/css!./lineNumbers';
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
import { editorLineNumbers, editorActiveLineNumber } from 'vs/editor/common/view/editorColorRegistry';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import * as platform from 'vs/base/common/platform';
import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';
@@ -162,7 +162,7 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
}
let lineIndex = lineNumber - startLineNumber;
if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
throw new Error('Unexpected render request');
return '';
}
return this._renderResult[lineIndex];
}
@@ -175,4 +175,8 @@ registerThemingParticipant((theme, collector) => {
if (lineNumbers) {
collector.addRule(`.monaco-editor .line-numbers { color: ${lineNumbers}; }`);
}
const activeLineNumber = theme.getColor(editorActiveLineNumber);
if (activeLineNumber) {
collector.addRule(`.monaco-editor .current-line ~ .line-numbers { color: ${activeLineNumber}; }`);
}
});

View File

@@ -228,9 +228,12 @@ export class ViewLine implements IVisibleLine {
isRegularASCII = strings.isBasicASCII(lineData.content);
}
if (isRegularASCII && lineData.content.length < 1000) {
if (isRegularASCII && lineData.content.length < 1000 && renderLineInput.lineTokens.getCount() < 100) {
// Browser rounding errors have been observed in Chrome and IE, so using the fast
// view line only for short lines. Please test before removing the length check...
// ---
// Another rounding error has been observed on Linux in VSCode, where <span> width
// rounding errors add up to an observable large number...
renderedViewLine = new FastRenderedViewLine(
this._renderedViewLine ? this._renderedViewLine.domNode : null,
renderLineInput,
@@ -278,8 +281,27 @@ export class ViewLine implements IVisibleLine {
}
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] {
startColumn = startColumn | 0; // @perf
endColumn = endColumn | 0; // @perf
startColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, startColumn));
endColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, endColumn));
const stopRenderingLineAfter = this._renderedViewLine.input.stopRenderingLineAfter | 0; // @perf
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter && endColumn > stopRenderingLineAfter) {
// This range is obviously not visible
return null;
}
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter) {
startColumn = stopRenderingLineAfter;
}
if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter) {
endColumn = stopRenderingLineAfter;
}
return this._renderedViewLine.getVisibleRangesForRange(startColumn, endColumn, context);
}
@@ -325,23 +347,6 @@ class FastRenderedViewLine implements IRenderedViewLine {
}
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] {
startColumn = startColumn | 0; // @perf
endColumn = endColumn | 0; // @perf
const stopRenderingLineAfter = this.input.stopRenderingLineAfter | 0; // @perf
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter && endColumn > stopRenderingLineAfter) {
// This range is obviously not visible
return null;
}
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter) {
startColumn = stopRenderingLineAfter;
}
if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter) {
endColumn = stopRenderingLineAfter;
}
const startPosition = this._getCharPosition(startColumn);
const endPosition = this._getCharPosition(endColumn);
return [new HorizontalRange(startPosition, endPosition - startPosition)];
@@ -432,23 +437,6 @@ class RenderedViewLine implements IRenderedViewLine {
* Visible ranges for a model range
*/
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] {
startColumn = startColumn | 0; // @perf
endColumn = endColumn | 0; // @perf
const stopRenderingLineAfter = this.input.stopRenderingLineAfter | 0; // @perf
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter && endColumn > stopRenderingLineAfter) {
// This range is obviously not visible
return null;
}
if (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter) {
startColumn = stopRenderingLineAfter;
}
if (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter) {
endColumn = stopRenderingLineAfter;
}
if (this._pixelOffsetCache !== null) {
// the text is LTR
let startOffset = this._readPixelOffset(startColumn, context);

View File

@@ -14,21 +14,21 @@
100% { background-color: none }
}*/
.monaco-editor .lines-content,
.monaco-editor .view-line,
.monaco-editor .view-lines {
.monaco-editor.safari .lines-content,
.monaco-editor.safari .view-line,
.monaco-editor.safari .view-lines {
-webkit-user-select: text;
-ms-user-select: text;
-khtml-user-select: text;
-moz-user-select: text;
-o-user-select: text;
user-select: text;
}
.monaco-editor.ie .lines-content,
.monaco-editor.ie .view-line,
.monaco-editor.ie .view-lines {
.monaco-editor .lines-content,
.monaco-editor .view-line,
.monaco-editor .view-lines {
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
}

View File

@@ -455,6 +455,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
// --- implementation
public updateLineWidths(): void {
this._updateLineWidths(false);
}
/**
* Updates the max line width if it is fast to compute.
* Returns true if all lines were taken into account.

View File

@@ -82,6 +82,10 @@ class MinimapOptions {
public readonly lineHeight: number;
/**
* container dom node left position (in CSS px)
*/
public readonly minimapLeft: number;
/**
* container dom node width (in CSS px)
*/
@@ -121,6 +125,7 @@ class MinimapOptions {
this.pixelRatio = pixelRatio;
this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
this.lineHeight = configuration.editor.lineHeight;
this.minimapLeft = layoutInfo.minimapLeft;
this.minimapWidth = layoutInfo.minimapWidth;
this.minimapHeight = layoutInfo.height;
@@ -138,6 +143,7 @@ class MinimapOptions {
&& this.pixelRatio === other.pixelRatio
&& this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth
&& this.lineHeight === other.lineHeight
&& this.minimapLeft === other.minimapLeft
&& this.minimapWidth === other.minimapWidth
&& this.minimapHeight === other.minimapHeight
&& this.canvasInnerWidth === other.canvasInnerWidth
@@ -456,7 +462,6 @@ export class Minimap extends ViewPart {
this._domNode.setPosition('absolute');
this._domNode.setAttribute('role', 'presentation');
this._domNode.setAttribute('aria-hidden', 'true');
this._domNode.setRight(this._context.configuration.editor.layoutInfo.verticalScrollbarWidth);
this._shadow = createFastDomNode(document.createElement('div'));
this._shadow.setClassName('minimap-shadow-hidden');
@@ -563,6 +568,7 @@ export class Minimap extends ViewPart {
}
private _applyLayout(): void {
this._domNode.setLeft(this._options.minimapLeft);
this._domNode.setWidth(this._options.minimapWidth);
this._domNode.setHeight(this._options.minimapHeight);
this._shadow.setHeight(this._options.minimapHeight);
@@ -654,6 +660,8 @@ export class Minimap extends ViewPart {
const renderMinimap = this._options.renderMinimap;
if (renderMinimap === RenderMinimap.None) {
this._shadow.setClassName('minimap-shadow-hidden');
this._sliderHorizontal.setWidth(0);
this._sliderHorizontal.setHeight(0);
return;
}
if (renderingCtx.scrollLeft + renderingCtx.viewportWidth >= renderingCtx.scrollWidth) {
@@ -868,10 +876,9 @@ export class Minimap extends ViewPart {
let charIndex = 0;
let tabsCharDelta = 0;
for (let tokenIndex = 0, tokensLen = tokens.length; tokenIndex < tokensLen; tokenIndex++) {
const token = tokens[tokenIndex];
const tokenEndIndex = token.endIndex;
const tokenColorId = token.getForeground();
for (let tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) {
const tokenEndIndex = tokens.getEndOffset(tokenIndex);
const tokenColorId = tokens.getForeground(tokenIndex);
const tokenColor = colorTracker.getColor(tokenColorId);
for (; charIndex < tokenEndIndex; charIndex++) {
@@ -927,4 +934,4 @@ registerThemingParticipant((theme, collector) => {
if (shadow) {
collector.addRule(`.monaco-editor .minimap-shadow-visible { box-shadow: ${shadow} -6px 0 6px -6px inset; }`);
}
});
});

View File

@@ -207,6 +207,7 @@ export class DecorationsOverviewRuler extends ViewPart {
this._domNode.setClassName('decorationsOverviewRuler');
this._domNode.setPosition('absolute');
this._domNode.setLayerHinting(true);
this._domNode.setAttribute('aria-hidden', 'true');
this._settings = null;
this._updateSettings(false);

View File

@@ -6,37 +6,41 @@
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
import { IOverviewRuler } from 'vs/editor/browser/editorBrowser';
import { OverviewRulerImpl } from 'vs/editor/browser/viewParts/overviewRuler/overviewRulerImpl';
import { ViewContext } from 'vs/editor/common/view/viewContext';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { OverviewRulerPosition } from 'vs/editor/common/config/editorOptions';
import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
import { OverviewRulerZone, OverviewZoneManager, ColorZone } from 'vs/editor/common/view/overviewZoneManager';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
export class OverviewRuler extends ViewEventHandler implements IOverviewRuler {
private _context: ViewContext;
private _overviewRuler: OverviewRulerImpl;
private _domNode: FastDomNode<HTMLCanvasElement>;
private _zoneManager: OverviewZoneManager;
constructor(context: ViewContext, cssClassName: string, minimumHeight: number, maximumHeight: number) {
constructor(context: ViewContext, cssClassName: string) {
super();
this._context = context;
this._overviewRuler = new OverviewRulerImpl(
0,
cssClassName,
this._context.viewLayout.getScrollHeight(),
this._context.configuration.editor.lineHeight,
this._context.configuration.editor.pixelRatio,
minimumHeight,
maximumHeight,
(lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber)
);
this._domNode = createFastDomNode(document.createElement('canvas'));
this._domNode.setClassName(cssClassName);
this._domNode.setPosition('absolute');
this._domNode.setLayerHinting(true);
this._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber));
this._zoneManager.setDOMWidth(0);
this._zoneManager.setDOMHeight(0);
this._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight());
this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight);
this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio);
this._context.addEventHandler(this);
}
public dispose(): void {
this._context.removeEventHandler(this);
this._overviewRuler.dispose();
this._zoneManager = null;
super.dispose();
}
@@ -44,40 +48,118 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler {
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
if (e.lineHeight) {
this._overviewRuler.setLineHeight(this._context.configuration.editor.lineHeight, true);
this._zoneManager.setLineHeight(this._context.configuration.editor.lineHeight);
this._render();
}
if (e.pixelRatio) {
this._overviewRuler.setPixelRatio(this._context.configuration.editor.pixelRatio, true);
this._zoneManager.setPixelRatio(this._context.configuration.editor.pixelRatio);
this._domNode.setWidth(this._zoneManager.getDOMWidth());
this._domNode.setHeight(this._zoneManager.getDOMHeight());
this._domNode.domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.domNode.height = this._zoneManager.getCanvasHeight();
this._render();
}
return true;
}
public onFlushed(e: viewEvents.ViewFlushedEvent): boolean {
this._render();
return true;
}
public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {
this._overviewRuler.setScrollHeight(e.scrollHeight, true);
return super.onScrollChanged(e) || e.scrollHeightChanged;
if (e.scrollHeightChanged) {
this._zoneManager.setOuterHeight(e.scrollHeight);
this._render();
}
return true;
}
public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {
this._render();
return true;
}
// ---- end view event handlers
public getDomNode(): HTMLElement {
return this._overviewRuler.getDomNode();
return this._domNode.domNode;
}
public setLayout(position: OverviewRulerPosition): void {
this._overviewRuler.setLayout(position, true);
this._domNode.setTop(position.top);
this._domNode.setRight(position.right);
let hasChanged = false;
hasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;
hasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;
if (hasChanged) {
this._domNode.setWidth(this._zoneManager.getDOMWidth());
this._domNode.setHeight(this._zoneManager.getDOMHeight());
this._domNode.domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.domNode.height = this._zoneManager.getCanvasHeight();
this._render();
}
}
public setZones(zones: OverviewRulerZone[]): void {
this._overviewRuler.setZones(zones, true);
this._zoneManager.setZones(zones);
this._render();
}
}
private _render(): boolean {
if (this._zoneManager.getOuterHeight() === 0) {
return false;
}
const width = this._zoneManager.getCanvasWidth();
const height = this._zoneManager.getCanvasHeight();
let colorZones = this._zoneManager.resolveColorZones();
let id2Color = this._zoneManager.getId2Color();
let ctx = this._domNode.domNode.getContext('2d');
ctx.clearRect(0, 0, width, height);
if (colorZones.length > 0) {
this._renderOneLane(ctx, colorZones, id2Color, width);
}
return true;
}
private _renderOneLane(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], width: number): void {
let currentColorId = 0;
let currentFrom = 0;
let currentTo = 0;
for (let i = 0, len = colorZones.length; i < len; i++) {
const zone = colorZones[i];
const zoneColorId = zone.colorId;
const zoneFrom = zone.from;
const zoneTo = zone.to;
if (zoneColorId !== currentColorId) {
ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);
currentColorId = zoneColorId;
ctx.fillStyle = id2Color[currentColorId];
currentFrom = zoneFrom;
currentTo = zoneTo;
} else {
if (currentTo >= zoneFrom) {
currentTo = Math.max(currentTo, zoneTo);
} else {
ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);
currentFrom = zoneFrom;
currentTo = zoneTo;
}
}
}
ctx.fillRect(0, currentFrom, width, currentTo - currentFrom);
}
}

View File

@@ -1,250 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { OverviewRulerLane } from 'vs/editor/common/editorCommon';
import { OverviewZoneManager, ColorZone, OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
import { Color } from 'vs/base/common/color';
import { OverviewRulerPosition } from 'vs/editor/common/config/editorOptions';
import { ThemeType, LIGHT } from 'vs/platform/theme/common/themeService';
export class OverviewRulerImpl {
private _canvasLeftOffset: number;
private _domNode: FastDomNode<HTMLCanvasElement>;
private _lanesCount: number;
private _zoneManager: OverviewZoneManager;
private _background: Color;
constructor(
canvasLeftOffset: number, cssClassName: string, scrollHeight: number, lineHeight: number,
pixelRatio: number, minimumHeight: number, maximumHeight: number,
getVerticalOffsetForLine: (lineNumber: number) => number
) {
this._canvasLeftOffset = canvasLeftOffset;
this._domNode = createFastDomNode(document.createElement('canvas'));
this._domNode.setClassName(cssClassName);
this._domNode.setPosition('absolute');
this._domNode.setLayerHinting(true);
this._lanesCount = 3;
this._background = null;
this._zoneManager = new OverviewZoneManager(getVerticalOffsetForLine);
this._zoneManager.setMinimumHeight(minimumHeight);
this._zoneManager.setMaximumHeight(maximumHeight);
this._zoneManager.setThemeType(LIGHT);
this._zoneManager.setDOMWidth(0);
this._zoneManager.setDOMHeight(0);
this._zoneManager.setOuterHeight(scrollHeight);
this._zoneManager.setLineHeight(lineHeight);
this._zoneManager.setPixelRatio(pixelRatio);
}
public dispose(): void {
this._zoneManager = null;
}
public setLayout(position: OverviewRulerPosition, render: boolean): void {
this._domNode.setTop(position.top);
this._domNode.setRight(position.right);
let hasChanged = false;
hasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;
hasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;
if (hasChanged) {
this._domNode.setWidth(this._zoneManager.getDOMWidth());
this._domNode.setHeight(this._zoneManager.getDOMHeight());
this._domNode.domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.domNode.height = this._zoneManager.getCanvasHeight();
if (render) {
this.render(true);
}
}
}
public getLanesCount(): number {
return this._lanesCount;
}
public setLanesCount(newLanesCount: number, render: boolean): void {
this._lanesCount = newLanesCount;
if (render) {
this.render(true);
}
}
public setThemeType(themeType: ThemeType, render: boolean): void {
this._zoneManager.setThemeType(themeType);
if (render) {
this.render(true);
}
}
public setUseBackground(background: Color, render: boolean): void {
this._background = background;
if (render) {
this.render(true);
}
}
public getDomNode(): HTMLCanvasElement {
return this._domNode.domNode;
}
public getPixelWidth(): number {
return this._zoneManager.getCanvasWidth();
}
public getPixelHeight(): number {
return this._zoneManager.getCanvasHeight();
}
public setScrollHeight(scrollHeight: number, render: boolean): void {
this._zoneManager.setOuterHeight(scrollHeight);
if (render) {
this.render(true);
}
}
public setLineHeight(lineHeight: number, render: boolean): void {
this._zoneManager.setLineHeight(lineHeight);
if (render) {
this.render(true);
}
}
public setPixelRatio(pixelRatio: number, render: boolean): void {
this._zoneManager.setPixelRatio(pixelRatio);
this._domNode.setWidth(this._zoneManager.getDOMWidth());
this._domNode.setHeight(this._zoneManager.getDOMHeight());
this._domNode.domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.domNode.height = this._zoneManager.getCanvasHeight();
if (render) {
this.render(true);
}
}
public setZones(zones: OverviewRulerZone[], render: boolean): void {
this._zoneManager.setZones(zones);
if (render) {
this.render(false);
}
}
public render(forceRender: boolean): boolean {
if (this._zoneManager.getOuterHeight() === 0) {
return false;
}
const width = this._zoneManager.getCanvasWidth();
const height = this._zoneManager.getCanvasHeight();
let colorZones = this._zoneManager.resolveColorZones();
let id2Color = this._zoneManager.getId2Color();
let ctx = this._domNode.domNode.getContext('2d');
if (this._background === null) {
ctx.clearRect(0, 0, width, height);
} else {
ctx.fillStyle = Color.Format.CSS.formatHex(this._background);
ctx.fillRect(0, 0, width, height);
}
if (colorZones.length > 0) {
let remainingWidth = width - this._canvasLeftOffset;
if (this._lanesCount >= 3) {
this._renderThreeLanes(ctx, colorZones, id2Color, remainingWidth);
} else if (this._lanesCount === 2) {
this._renderTwoLanes(ctx, colorZones, id2Color, remainingWidth);
} else if (this._lanesCount === 1) {
this._renderOneLane(ctx, colorZones, id2Color, remainingWidth);
}
}
return true;
}
private _renderOneLane(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], w: number): void {
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Left | OverviewRulerLane.Center | OverviewRulerLane.Right, this._canvasLeftOffset, w);
}
private _renderTwoLanes(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], w: number): void {
let leftWidth = Math.floor(w / 2);
let rightWidth = w - leftWidth;
let leftOffset = this._canvasLeftOffset;
let rightOffset = this._canvasLeftOffset + leftWidth;
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Left | OverviewRulerLane.Center, leftOffset, leftWidth);
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Right, rightOffset, rightWidth);
}
private _renderThreeLanes(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], w: number): void {
let leftWidth = Math.floor(w / 3);
let rightWidth = Math.floor(w / 3);
let centerWidth = w - leftWidth - rightWidth;
let leftOffset = this._canvasLeftOffset;
let centerOffset = this._canvasLeftOffset + leftWidth;
let rightOffset = this._canvasLeftOffset + leftWidth + centerWidth;
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Left, leftOffset, leftWidth);
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Center, centerOffset, centerWidth);
this._renderVerticalPatch(ctx, colorZones, id2Color, OverviewRulerLane.Right, rightOffset, rightWidth);
}
private _renderVerticalPatch(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], laneMask: number, xpos: number, width: number): void {
let currentColorId = 0;
let currentFrom = 0;
let currentTo = 0;
for (let i = 0, len = colorZones.length; i < len; i++) {
let zone = colorZones[i];
if (!(zone.position & laneMask)) {
continue;
}
let zoneColorId = zone.colorId;
let zoneFrom = zone.from;
let zoneTo = zone.to;
if (zoneColorId !== currentColorId) {
ctx.fillRect(xpos, currentFrom, width, currentTo - currentFrom);
currentColorId = zoneColorId;
ctx.fillStyle = id2Color[currentColorId];
currentFrom = zoneFrom;
currentTo = zoneTo;
} else {
if (currentTo >= zoneFrom) {
currentTo = Math.max(currentTo, zoneTo);
} else {
ctx.fillRect(xpos, currentFrom, width, currentTo - currentFrom);
currentFrom = zoneFrom;
currentTo = zoneTo;
}
}
}
ctx.fillRect(xpos, currentFrom, width, currentTo - currentFrom);
}
}

View File

@@ -387,7 +387,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
}
let lineIndex = lineNumber - startLineNumber;
if (lineIndex < 0 || lineIndex >= this._renderResult.length) {
throw new Error('Unexpected render request');
return '';
}
return this._renderResult[lineIndex];
}

View File

@@ -23,53 +23,44 @@ export interface IViewCursorRenderData {
}
class ViewCursorRenderData {
public readonly top: number;
public readonly left: number;
public readonly width: number;
public readonly textContent: string;
constructor(top: number, left: number, width: number, textContent: string) {
this.top = top;
this.left = left;
this.width = width;
this.textContent = textContent;
}
constructor(
public readonly top: number,
public readonly left: number,
public readonly width: number,
public readonly height: number,
public readonly textContent: string
) { }
}
export class ViewCursor {
private readonly _context: ViewContext;
private readonly _isSecondary: boolean;
private readonly _domNode: FastDomNode<HTMLElement>;
private _cursorStyle: TextEditorCursorStyle;
private _lineCursorWidth: number;
private _lineHeight: number;
private _typicalHalfwidthCharacterWidth: number;
private _isVisible: boolean;
private _position: Position;
private _isInEditableRange: boolean;
private _lastRenderedContent: string;
private _renderData: ViewCursorRenderData;
constructor(context: ViewContext, isSecondary: boolean) {
constructor(context: ViewContext) {
this._context = context;
this._isSecondary = isSecondary;
this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle;
this._lineHeight = this._context.configuration.editor.lineHeight;
this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth;
this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth);
this._isVisible = true;
// Create the dom node
this._domNode = createFastDomNode(document.createElement('div'));
if (this._isSecondary) {
this._domNode.setClassName('cursor secondary');
} else {
this._domNode.setClassName('cursor');
}
this._domNode.setClassName('cursor');
this._domNode.setHeight(this._lineHeight);
this._domNode.setTop(0);
this._domNode.setLeft(0);
@@ -77,7 +68,6 @@ export class ViewCursor {
this._domNode.setDisplay('none');
this.updatePosition(new Position(1, 1));
this._isInEditableRange = true;
this._lastRenderedContent = '';
this._renderData = null;
@@ -87,10 +77,6 @@ export class ViewCursor {
return this._domNode;
}
public getIsInEditableRange(): boolean {
return this._isInEditableRange;
}
public getPosition(): Position {
return this._position;
}
@@ -113,23 +99,26 @@ export class ViewCursor {
if (e.lineHeight) {
this._lineHeight = this._context.configuration.editor.lineHeight;
}
if (e.viewInfo) {
this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle;
}
if (e.fontInfo) {
Configuration.applyFontInfo(this._domNode, this._context.configuration.editor.fontInfo);
this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth;
}
if (e.viewInfo) {
this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle;
this._lineCursorWidth = Math.min(this._context.configuration.editor.viewInfo.cursorWidth, this._typicalHalfwidthCharacterWidth);
}
return true;
}
public onCursorPositionChanged(position: Position, isInEditableRange: boolean): boolean {
public onCursorPositionChanged(position: Position): boolean {
this.updatePosition(position);
this._isInEditableRange = isInEditableRange;
return true;
}
private _prepareRender(ctx: RenderingContext): ViewCursorRenderData {
let textContent = '';
if (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) {
const visibleRange = ctx.visibleRangeForPosition(this._position);
if (!visibleRange) {
@@ -138,12 +127,16 @@ export class ViewCursor {
}
let width: number;
if (this._cursorStyle === TextEditorCursorStyle.Line) {
width = dom.computeScreenAwareSize(2);
width = dom.computeScreenAwareSize(this._lineCursorWidth > 0 ? this._lineCursorWidth : 2);
if (width > 2) {
const lineContent = this._context.model.getLineContent(this._position.lineNumber);
textContent = lineContent.charAt(this._position.column - 1);
}
} else {
width = dom.computeScreenAwareSize(1);
}
const top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;
return new ViewCursorRenderData(top, visibleRange.left, width, '');
return new ViewCursorRenderData(top, visibleRange.left, width, this._lineHeight, textContent);
}
const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + 1), false);
@@ -156,14 +149,21 @@ export class ViewCursor {
const range = visibleRangeForCharacter[0].ranges[0];
const width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width;
let textContent = '';
if (this._cursorStyle === TextEditorCursorStyle.Block) {
const lineContent = this._context.model.getLineContent(this._position.lineNumber);
textContent = lineContent.charAt(this._position.column - 1);
}
const top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;
return new ViewCursorRenderData(top, range.left, width, textContent);
let top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;
let height = this._lineHeight;
// Underline might interfere with clicking
if (this._cursorStyle === TextEditorCursorStyle.Underline || this._cursorStyle === TextEditorCursorStyle.UnderlineThin) {
top += this._lineHeight - 2;
height = 2;
}
return new ViewCursorRenderData(top, range.left, width, height, textContent);
}
public prepareRender(ctx: RenderingContext): void {
@@ -185,14 +185,14 @@ export class ViewCursor {
this._domNode.setTop(this._renderData.top);
this._domNode.setLeft(this._renderData.left);
this._domNode.setWidth(this._renderData.width);
this._domNode.setLineHeight(this._lineHeight);
this._domNode.setHeight(this._lineHeight);
this._domNode.setLineHeight(this._renderData.height);
this._domNode.setHeight(this._renderData.height);
return {
domNode: this._domNode.domNode,
position: this._position,
contentLeft: this._renderData.left,
height: this._lineHeight,
height: this._renderData.height,
width: 2
};
}

View File

@@ -10,9 +10,7 @@
.monaco-editor .cursors-layer > .cursor {
position: absolute;
cursor: text;
}
.monaco-editor .cursors-layer > .cursor.secondary {
opacity: 0.6;
overflow: hidden;
}
/* -- block-outline-style -- */

View File

@@ -49,7 +49,7 @@ export class ViewCursors extends ViewPart {
this._cursorStyle = this._context.configuration.editor.viewInfo.cursorStyle;
this._selectionIsEmpty = true;
this._primaryCursor = new ViewCursor(this._context, false);
this._primaryCursor = new ViewCursor(this._context);
this._secondaryCursors = [];
this._renderData = [];
@@ -101,15 +101,15 @@ export class ViewCursors extends ViewPart {
}
return true;
}
private _onCursorPositionChanged(position: Position, secondaryPositions: Position[], isInEditableRange: boolean): void {
this._primaryCursor.onCursorPositionChanged(position, isInEditableRange);
private _onCursorPositionChanged(position: Position, secondaryPositions: Position[]): void {
this._primaryCursor.onCursorPositionChanged(position);
this._updateBlinking();
if (this._secondaryCursors.length < secondaryPositions.length) {
// Create new cursors
let addCnt = secondaryPositions.length - this._secondaryCursors.length;
for (let i = 0; i < addCnt; i++) {
let newCursor = new ViewCursor(this._context, true);
let newCursor = new ViewCursor(this._context);
this._domNode.domNode.insertBefore(newCursor.getDomNode().domNode, this._primaryCursor.getDomNode().domNode.nextSibling);
this._secondaryCursors.push(newCursor);
}
@@ -123,7 +123,7 @@ export class ViewCursors extends ViewPart {
}
for (let i = 0; i < secondaryPositions.length; i++) {
this._secondaryCursors[i].onCursorPositionChanged(secondaryPositions[i], isInEditableRange);
this._secondaryCursors[i].onCursorPositionChanged(secondaryPositions[i]);
}
}
@@ -132,7 +132,7 @@ export class ViewCursors extends ViewPart {
for (let i = 0, len = e.selections.length; i < len; i++) {
positions[i] = e.selections[i].getPosition();
}
this._onCursorPositionChanged(positions[0], positions.slice(1), e.isInEditableRange);
this._onCursorPositionChanged(positions[0], positions.slice(1));
const selectionIsEmpty = e.selections[0].isEmpty();
if (this._selectionIsEmpty !== selectionIsEmpty) {
@@ -198,7 +198,7 @@ export class ViewCursors extends ViewPart {
if (!this._editorHasFocus) {
return TextEditorCursorBlinkingStyle.Hidden;
}
if (this._readOnly || !this._primaryCursor.getIsInEditableRange()) {
if (this._readOnly) {
return TextEditorCursorBlinkingStyle.Solid;
}
return this._cursorBlinking;

View File

@@ -32,6 +32,7 @@ import { editorErrorForeground, editorErrorBorder, editorWarningForeground, edit
import { Color } from 'vs/base/common/color';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { ClassName } from 'vs/editor/common/model/intervalTree';
import { ITextModel, IModelDecorationOptions } from 'vs/editor/common/model';
export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
@@ -157,8 +158,8 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
super.dispose();
}
public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): editorBrowser.IOverviewRuler {
return this._view.createOverviewRuler(cssClassName, minimumHeight, maximumHeight);
public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler {
return this._view.createOverviewRuler(cssClassName);
}
public getDomNode(): HTMLElement {
@@ -326,7 +327,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
}
_attachModel(model: editorCommon.IModel): void {
_attachModel(model: ITextModel): void {
this._view = null;
super._attachModel(model);
@@ -392,7 +393,17 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
viewEventBus.onKeyDown = (e) => this._onKeyDown.fire(e);
}
protected _detachModel(): editorCommon.IModel {
public restoreViewState(s: editorCommon.ICodeEditorViewState): void {
super.restoreViewState(s);
if (!this.cursor || !this.hasView) {
return;
}
if (s && s.cursorState && s.viewState) {
this._view.restoreState(this.viewModel.viewLayout.reduceRestoreState(s.viewState));
}
}
protected _detachModel(): ITextModel {
let removeDomNode: HTMLElement = null;
if (this._view) {
@@ -420,7 +431,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
this._codeEditorService.removeDecorationType(key);
}
protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
protected _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions {
return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
}

View File

@@ -11,7 +11,6 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { Disposable } from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
import * as dom from 'vs/base/browser/dom';
import Severity from 'vs/base/common/severity';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { ISashEvent, IVerticalSashLayoutProvider, Sash } from 'vs/base/browser/ui/sash/sash';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -24,7 +23,7 @@ import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { CodeEditor } from 'vs/editor/browser/codeEditor';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
@@ -38,14 +37,15 @@ import { scrollbarShadow, diffInserted, diffRemoved, defaultInsertColor, default
import { Color } from 'vs/base/common/color';
import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
import URI from 'vs/base/common/uri';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { IModelDeltaDecoration, IModelDecorationsChangeAccessor, ITextModel } from 'vs/editor/common/model';
import { INotificationService } from 'vs/platform/notification/common/notification';
interface IEditorDiffDecorations {
decorations: editorCommon.IModelDeltaDecoration[];
decorations: IModelDeltaDecoration[];
overviewZones: OverviewRulerZone[];
}
@@ -100,7 +100,7 @@ class VisualEditorState {
// (2) Model decorations
if (this._decorations.length > 0) {
editor.changeDecorations((changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => {
editor.changeDecorations((changeAccessor: IModelDecorationsChangeAccessor) => {
changeAccessor.deltaDecorations(this._decorations, []);
});
}
@@ -191,7 +191,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
protected _contextKeyService: IContextKeyService;
private _codeEditorService: ICodeEditorService;
private _themeService: IThemeService;
private readonly _messageService: IMessageService;
private _notificationService: INotificationService;
private _reviewPane: DiffReview;
@@ -203,16 +203,16 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IThemeService themeService: IThemeService,
@IMessageService messageService: IMessageService
@INotificationService notificationService: INotificationService
) {
super();
this._editorWorkerService = editorWorkerService;
this._codeEditorService = codeEditorService;
this._contextKeyService = contextKeyService.createScoped(domElement);
this._contextKeyService = this._register(contextKeyService.createScoped(domElement));
this._contextKeyService.createKey('isInDiffEditor', true);
this._themeService = themeService;
this._messageService = messageService;
this._notificationService = notificationService;
this.id = (++DIFF_EDITOR_ID);
@@ -313,14 +313,14 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._setStrategy(new DiffEdtorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
}
this._codeEditorService.addDiffEditor(this);
this._register(themeService.onThemeChange(t => {
if (this._strategy && this._strategy.applyColors(t)) {
this._updateDecorationsRunner.schedule();
}
this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide);
}));
this._codeEditorService.addDiffEditor(this);
}
public get ignoreTrimWhitespace(): boolean {
@@ -361,14 +361,14 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
this._originalOverviewRuler.dispose();
}
this._originalOverviewRuler = this.originalEditor.createOverviewRuler('original diffOverviewRuler', 4, Number.MAX_VALUE);
this._originalOverviewRuler = this.originalEditor.createOverviewRuler('original diffOverviewRuler');
this._overviewDomElement.appendChild(this._originalOverviewRuler.getDomNode());
if (this._modifiedOverviewRuler) {
this._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());
this._modifiedOverviewRuler.dispose();
}
this._modifiedOverviewRuler = this.modifiedEditor.createOverviewRuler('modified diffOverviewRuler', 4, Number.MAX_VALUE);
this._modifiedOverviewRuler = this.modifiedEditor.createOverviewRuler('modified diffOverviewRuler');
this._overviewDomElement.appendChild(this._modifiedOverviewRuler.getDomNode());
this._layoutOverviewRulers();
@@ -465,20 +465,37 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
public dispose(): void {
this._codeEditorService.removeDiffEditor(this);
if (this._beginUpdateDecorationsTimeout !== -1) {
window.clearTimeout(this._beginUpdateDecorationsTimeout);
this._beginUpdateDecorationsTimeout = -1;
}
window.clearInterval(this._measureDomElementToken);
this._cleanViewZonesAndDecorations();
this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
this._originalOverviewRuler.dispose();
this._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());
this._modifiedOverviewRuler.dispose();
this._overviewDomElement.removeChild(this._overviewViewportDomElement.domNode);
this._containerDomElement.removeChild(this._overviewDomElement);
this._containerDomElement.removeChild(this._originalDomNode);
this.originalEditor.dispose();
this._containerDomElement.removeChild(this._modifiedDomNode);
this.modifiedEditor.dispose();
this._strategy.dispose();
this._containerDomElement.removeChild(this._reviewPane.domNode.domNode);
this._containerDomElement.removeChild(this._reviewPane.shadow.domNode);
this._containerDomElement.removeChild(this._reviewPane.actionBarContainer.domNode);
this._reviewPane.dispose();
this._domElement.removeChild(this._containerDomElement);
this._onDidDispose.fire();
super.dispose();
@@ -746,7 +763,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this.modifiedEditor.trigger(source, handlerId, payload);
}
public changeDecorations(callback: (changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => any): any {
public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
return this.modifiedEditor.changeDecorations(callback);
}
@@ -852,7 +869,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
) {
this._lastOriginalWarning = currentOriginalModel.uri;
this._lastModifiedWarning = currentModifiedModel.uri;
this._messageService.show(Severity.Warning, nls.localize("diff.tooLarge", "Cannot compare files because one file is too large."));
this._notificationService.warn(nls.localize("diff.tooLarge", "Cannot compare files because one file is too large."));
}
return;
}
@@ -1594,6 +1611,7 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
}
_getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._removeColor.toString();
let result: IEditorDiffDecorations = {
decorations: [],
@@ -1614,16 +1632,10 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Number.MAX_VALUE, DECORATIONS.charDeleteWholeLine));
}
let color = this._removeColor.toString();
result.overviewZones.push(new OverviewRulerZone(
lineChange.originalStartLineNumber,
lineChange.originalEndLineNumber,
editorCommon.OverviewRulerLane.Full,
0,
color,
color,
color
overviewZoneColor
));
if (lineChange.charChanges) {
@@ -1659,6 +1671,7 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
}
_getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._insertColor.toString();
let result: IEditorDiffDecorations = {
decorations: [],
@@ -1679,15 +1692,10 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
if (!isChangeOrDelete(lineChange) || !lineChange.charChanges) {
result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE, DECORATIONS.charInsertWholeLine));
}
let color = this._insertColor.toString();
result.overviewZones.push(new OverviewRulerZone(
lineChange.modifiedStartLineNumber,
lineChange.modifiedEndLineNumber,
editorCommon.OverviewRulerLane.Full,
0,
color,
color,
color
overviewZoneColor
));
if (lineChange.charChanges) {
@@ -1783,6 +1791,8 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
}
_getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._removeColor.toString();
let result: IEditorDiffDecorations = {
decorations: [],
overviewZones: []
@@ -1798,15 +1808,10 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
options: DECORATIONS.lineDeleteMargin
});
let color = this._removeColor.toString();
result.overviewZones.push(new OverviewRulerZone(
lineChange.originalStartLineNumber,
lineChange.originalEndLineNumber,
editorCommon.OverviewRulerLane.Full,
0,
color,
color,
color
overviewZoneColor
));
}
}
@@ -1815,6 +1820,7 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
}
_getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._insertColor.toString();
let result: IEditorDiffDecorations = {
decorations: [],
@@ -1833,15 +1839,10 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)
});
let color = this._insertColor.toString();
result.overviewZones.push(new OverviewRulerZone(
lineChange.modifiedStartLineNumber,
lineChange.modifiedEndLineNumber,
editorCommon.OverviewRulerLane.Full,
0,
color,
color,
color
overviewZoneColor
));
if (lineChange.charChanges) {
@@ -1887,7 +1888,7 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
class InlineViewZonesComputer extends ViewZonesComputer {
private originalModel: editorCommon.IModel;
private originalModel: ITextModel;
private modifiedEditorConfiguration: editorOptions.InternalEditorOptions;
private modifiedEditorTabSize: number;
private renderIndicators: boolean;
@@ -1962,7 +1963,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
};
}
private renderOriginalLine(count: number, originalModel: editorCommon.IModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): void {
private renderOriginalLine(count: number, originalModel: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): void {
let lineContent = originalModel.getLineContent(lineNumber);
let actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);
@@ -1973,6 +1974,12 @@ class InlineViewZonesComputer extends ViewZonesComputer {
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
const tokens = new Uint32Array(2);
tokens[0] = lineContent.length;
tokens[1] = defaultMetadata;
const lineTokens = new LineTokens(tokens, lineContent);
sb.appendASCIIString('<div class="view-line');
if (decorations.length === 0) {
// No char changes
@@ -1987,7 +1994,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
lineContent,
originalModel.mightContainRTL(),
0,
[new ViewLineToken(lineContent.length, defaultMetadata)],
lineTokens,
actualDecorations,
tabSize,
config.fontInfo.spaceWidth,

View File

@@ -25,7 +25,7 @@ export interface Options {
alwaysRevealFirst?: boolean;
}
var defaultOptions: Options = {
const defaultOptions: Options = {
followsCaret: true,
ignoreCharChanges: true,
alwaysRevealFirst: true
@@ -84,7 +84,7 @@ export class DiffNavigator {
}
private _init(): void {
var changes = this._editor.getLineChanges();
let changes = this._editor.getLineChanges();
if (!changes) {
return;
}
@@ -149,10 +149,10 @@ export class DiffNavigator {
}
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;
let found = false;
let position = this._editor.getPosition();
for (let i = 0, len = this.ranges.length; i < len && !found; i++) {
let range = this.ranges[i].range;
if (position.isBeforeOrEqual(range.getStartPosition())) {
this.nextIdx = i + (fwd ? 0 : -1);
found = true;
@@ -189,10 +189,10 @@ export class DiffNavigator {
}
}
var info = this.ranges[this.nextIdx];
let info = this.ranges[this.nextIdx];
this.ignoreSelectionChange = true;
try {
var pos = info.range.getStartPosition();
let pos = info.range.getStartPosition();
this._editor.setPosition(pos);
this._editor.revealPositionInCenter(pos, ScrollType.Smooth);
} finally {

View File

@@ -11,7 +11,7 @@ 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 { LineTokens } from 'vs/editor/common/core/lineTokens';
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';
@@ -28,6 +28,7 @@ import { registerEditorAction, EditorAction, ServicesAccessor } from 'vs/editor/
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';
const DIFF_LINES_PADDING = 3;
@@ -607,8 +608,8 @@ export class DiffReview extends Disposable {
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
originalOpts: editorOptions.InternalEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions,
modifiedOpts: editorOptions.InternalEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions
): void {
const type = diffEntry.getType();
@@ -722,7 +723,7 @@ export class DiffReview extends Disposable {
}
}
private static _renderLine(model: editorCommon.IModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number): string {
private static _renderLine(model: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number): string {
const lineContent = model.getLineContent(lineNumber);
const defaultMetadata = (
@@ -731,12 +732,18 @@ export class DiffReview extends Disposable {
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
const tokens = new Uint32Array(2);
tokens[0] = lineContent.length;
tokens[1] = defaultMetadata;
const lineTokens = new LineTokens(tokens, lineContent);
const r = renderViewLine(new RenderLineInput(
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
lineContent,
model.mightContainRTL(),
0,
[new ViewLineToken(lineContent.length, defaultMetadata)],
lineTokens,
[],
tabSize,
config.fontInfo.spaceWidth,

View File

@@ -15,7 +15,7 @@ import { IConfigurationChangedEvent, IEditorOptions, IDiffEditorOptions } from '
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';
import { INotificationService } from 'vs/platform/notification/common/notification';
export class EmbeddedCodeEditorWidget extends CodeEditor {
@@ -72,9 +72,9 @@ export class EmbeddedDiffEditorWidget extends DiffEditorWidget {
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IThemeService themeService: IThemeService,
@IMessageService messageService: IMessageService
@INotificationService notificationService: INotificationService
) {
super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, messageService);
super(domElement, parentEditor.getRawConfiguration(), editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService);
this._parentEditor = parentEditor;
this._overwriteOptions = options;