From 37c7bdb4f6bad43e1a66b9c0b4cb36f647eed0ef Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 30 Apr 2018 15:17:20 +0200 Subject: [PATCH] Eliminate CommonCodeEditor --- src/vs/editor/browser/view/viewController.ts | 6 +- src/vs/editor/browser/view/viewImpl.ts | 4 +- .../editor/browser/widget/codeEditorWidget.ts | 1315 ++++++++++++++++- src/vs/editor/common/commonCodeEditor.ts | 1270 ---------------- .../common/config/commonEditorConfig.ts | 3 + src/vs/editor/common/editorCommon.ts | 6 +- src/vs/editor/test/browser/testCodeEditor.ts | 3 +- 7 files changed, 1265 insertions(+), 1342 deletions(-) delete mode 100644 src/vs/editor/common/commonCodeEditor.ts diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 31233148de5..9b436287c58 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -11,7 +11,7 @@ import { IEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; import { CoreNavigationCommands, CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands'; -import { Configuration } from 'vs/editor/browser/config/configuration'; +import { IConfiguration } from 'vs/editor/common/editorCommon'; export interface ExecCoreEditorCommandFunc { (editorCommand: CoreEditorCommand, args: any): void; @@ -47,14 +47,14 @@ export interface ICommandDelegate { export class ViewController { - private readonly configuration: Configuration; + private readonly configuration: IConfiguration; private readonly viewModel: IViewModel; private readonly _execCoreEditorCommandFunc: ExecCoreEditorCommandFunc; private readonly outgoingEvents: ViewOutgoingEvents; private readonly commandDelegate: ICommandDelegate; constructor( - configuration: Configuration, + configuration: IConfiguration, viewModel: IViewModel, execCommandFunc: ExecCoreEditorCommandFunc, outgoingEvents: ViewOutgoingEvents, diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index ce4b080de4a..f619f1adef4 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -10,7 +10,7 @@ import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { Range } from 'vs/editor/common/core/range'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; -import { Configuration } from 'vs/editor/browser/config/configuration'; +import { IConfiguration } from 'vs/editor/common/editorCommon'; import { TextAreaHandler, ITextAreaHandlerHelper } from 'vs/editor/browser/controller/textAreaHandler'; import { PointerHandler } from 'vs/editor/browser/controller/pointerHandler'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; @@ -93,7 +93,7 @@ export class View extends ViewEventHandler { constructor( commandDelegate: ICommandDelegate, - configuration: Configuration, + configuration: IConfiguration, themeService: IThemeService, model: IViewModel, cursor: Cursor, diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 7103fb97b39..a7492e4662c 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -6,37 +6,107 @@ import 'vs/css!./media/editor'; import 'vs/css!./media/tokens'; +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { Event, Emitter } from 'vs/base/common/event'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; -import * as dom from 'vs/base/browser/dom'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor'; -import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { EditorAction, EditorExtensionsRegistry, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Configuration } from 'vs/editor/browser/config/configuration'; +import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; +import { CursorColumns, ICursors, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon'; +import { Position, IPosition } from 'vs/editor/common/core/position'; +import { Range, IRange } from 'vs/editor/common/core/range'; +import { Selection, ISelection } from 'vs/editor/common/core/selection'; +import * as editorCommon from 'vs/editor/common/editorCommon'; +import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; +import { hash } from 'vs/base/common/hash'; +import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; +import * as editorOptions from 'vs/editor/common/config/editorOptions'; +import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; +import * as modes from 'vs/editor/common/modes'; +import { Schemas } from 'vs/base/common/network'; +import { ITextModel, EndOfLinePreference, IIdentifiedSingleEditOperation, IModelDecorationsChangeAccessor, IModelDecoration, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; -import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { Event, Emitter } from 'vs/base/common/event'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl'; +import { IEditorContributionCtor, EditorAction, EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { InternalEditorAction } from 'vs/editor/common/editorAction'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { IPosition, Position } from 'vs/editor/common/core/position'; +import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands'; -import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground, editorHintForeground, editorHintBorder } from 'vs/editor/common/view/editorColorRegistry'; 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'; -import { ICommandDelegate } from 'vs/editor/browser/view/viewController'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor { +let EDITOR_ID = 0; + +export abstract class CodeEditorWidget extends Disposable implements editorBrowser.ICodeEditor { + + //#region Eventing + private readonly _onDidDispose: Emitter = this._register(new Emitter()); + public readonly onDidDispose: Event = this._onDidDispose.event; + + private readonly _onDidChangeModelContent: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelContent: Event = this._onDidChangeModelContent.event; + + private readonly _onDidChangeModelLanguage: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event; + + private readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguageConfiguration.event; + + private readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event; + + private readonly _onDidChangeModelDecorations: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelDecorations: Event = this._onDidChangeModelDecorations.event; + + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + + protected readonly _onDidChangeModel: Emitter = this._register(new Emitter()); + public readonly onDidChangeModel: Event = this._onDidChangeModel.event; + + private readonly _onDidChangeCursorPosition: Emitter = this._register(new Emitter()); + public readonly onDidChangeCursorPosition: Event = this._onDidChangeCursorPosition.event; + + private readonly _onDidChangeCursorSelection: Emitter = this._register(new Emitter()); + public readonly onDidChangeCursorSelection: Event = this._onDidChangeCursorSelection.event; + + private readonly _onDidAttemptReadOnlyEdit: Emitter = this._register(new Emitter()); + public readonly onDidAttemptReadOnlyEdit: Event = this._onDidAttemptReadOnlyEdit.event; + + private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); + public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; + + protected _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); + public readonly onDidFocusEditorText: Event = this._editorTextFocus.onDidChangeToTrue; + public readonly onDidBlurEditorText: Event = this._editorTextFocus.onDidChangeToFalse; + + protected _editorFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); + public readonly onDidFocusEditor: Event = this._editorFocus.onDidChangeToTrue; + public readonly onDidBlurEditor: Event = this._editorFocus.onDidChangeToFalse; + + private readonly _onWillType: Emitter = this._register(new Emitter()); + public readonly onWillType = this._onWillType.event; + + private readonly _onDidType: Emitter = this._register(new Emitter()); + public readonly onDidType = this._onDidType.event; + + private readonly _onDidPaste: Emitter = this._register(new Emitter()); + public readonly onDidPaste = this._onDidPaste.event; private readonly _onMouseUp: Emitter = this._register(new Emitter()); public readonly onMouseUp: Event = this._onMouseUp.event; @@ -70,24 +140,48 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito private readonly _onDidChangeViewZones: Emitter = this._register(new Emitter()); public readonly onDidChangeViewZones: Event = this._onDidChangeViewZones.event; + //#endregion - private _codeEditorService: ICodeEditorService; - private _commandService: ICommandService; - private _themeService: IThemeService; + public readonly isSimpleWidget: boolean; - protected domElement: HTMLElement; - private _focusTracker: CodeEditorWidgetFocusTracker; + private readonly domElement: HTMLElement; + private readonly id: number; + private readonly _configuration: editorCommon.IConfiguration; + + protected _contributions: { [key: string]: editorCommon.IEditorContribution; }; + protected _actions: { [key: string]: editorCommon.IEditorAction; }; + + // --- Members logically associated to a model + protected model: ITextModel; + private listenersToRemove: IDisposable[]; + private hasView: boolean; - _configuration: Configuration; + private viewModel: ViewModel; + protected cursor: Cursor; + + protected readonly _instantiationService: IInstantiationService; + protected readonly _contextKeyService: IContextKeyService; + private readonly _notificationService: INotificationService; + private readonly _codeEditorService: ICodeEditorService; + private readonly _commandService: ICommandService; + private readonly _themeService: IThemeService; + + private _focusTracker: CodeEditorWidgetFocusTracker; private contentWidgets: { [key: string]: IContentWidgetData; }; private overlayWidgets: { [key: string]: IOverlayWidgetData; }; - _view: View; + protected _view: View; + + /** + * map from "parent" decoration type to live decoration ids. + */ + private _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] }; + private _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } }; constructor( domElement: HTMLElement, - options: IEditorOptions, + options: editorOptions.IEditorOptions, isSimpleWidget: boolean, @IInstantiationService instantiationService: IInstantiationService, @ICodeEditorService codeEditorService: ICodeEditorService, @@ -96,10 +190,37 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito @IThemeService themeService: IThemeService, @INotificationService notificationService: INotificationService ) { - super(domElement, options, isSimpleWidget, instantiationService, contextKeyService, notificationService); + super(); + this.domElement = domElement; + this.id = (++EDITOR_ID); + this._decorationTypeKeysToIds = {}; + this._decorationTypeSubtypes = {}; + this.isSimpleWidget = isSimpleWidget; + + options = options || {}; + this._configuration = this._register(this._createConfiguration(options)); + this._register(this._configuration.onDidChange((e) => { + this._onDidChangeConfiguration.fire(e); + + if (e.layoutInfo) { + this._onDidLayoutChange.fire(this._configuration.editor.layoutInfo); + } + })); + + this._contextKeyService = this._register(contextKeyService.createScoped(this.domElement)); + this._notificationService = notificationService; this._codeEditorService = codeEditorService; this._commandService = commandService; this._themeService = themeService; + this._register(new EditorContextKeysManager(this, this._contextKeyService)); + this._register(new EditorModeContext(this, this._contextKeyService)); + + this._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])); + + this._attachModel(null); + + this._contributions = {}; + this._actions = {}; this._focusTracker = new CodeEditorWidgetFocusTracker(domElement); this._focusTracker.onChange(() => { @@ -139,11 +260,19 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito this._codeEditorService.addCodeEditor(this); } + protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration { + return new Configuration(options, this.domElement); + } + protected abstract _getContributions(): IEditorContributionCtor[]; protected abstract _getActions(): EditorAction[]; - protected _createConfiguration(options: IEditorOptions): CommonEditorConfiguration { - return new Configuration(options, this.domElement); + public getId(): string { + return this.getEditorType() + ':' + this.id; + } + + public getEditorType(): string { + return editorCommon.EditorType.ICodeEditor; } public dispose(): void { @@ -153,9 +282,781 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito this.overlayWidgets = {}; this._focusTracker.dispose(); + + let keys = Object.keys(this._contributions); + for (let i = 0, len = keys.length; i < len; i++) { + let contributionId = keys[i]; + this._contributions[contributionId].dispose(); + } + this._contributions = {}; + + // editor actions don't need to be disposed + this._actions = {}; + this._removeDecorationTypes(); + this._postDetachModelCleanup(this._detachModel()); + + this._onDidDispose.fire(); + super.dispose(); } + public invokeWithinContext(fn: (accessor: ServicesAccessor) => T): T { + return this._instantiationService.invokeFunction(fn); + } + + public updateOptions(newOptions: editorOptions.IEditorOptions): void { + this._configuration.updateOptions(newOptions); + } + + public getConfiguration(): editorOptions.InternalEditorOptions { + return this._configuration.editor; + } + + public getRawConfiguration(): editorOptions.IEditorOptions { + return this._configuration.getRawOptions(); + } + + public getValue(options: { preserveBOM: boolean; lineEnding: string; } = null): string { + if (this.model) { + let preserveBOM: boolean = (options && options.preserveBOM) ? true : false; + let eolPreference = EndOfLinePreference.TextDefined; + if (options && options.lineEnding && options.lineEnding === '\n') { + eolPreference = EndOfLinePreference.LF; + } else if (options && options.lineEnding && options.lineEnding === '\r\n') { + eolPreference = EndOfLinePreference.CRLF; + } + return this.model.getValue(eolPreference, preserveBOM); + } + return ''; + } + + public setValue(newValue: string): void { + if (this.model) { + this.model.setValue(newValue); + } + } + + public getModel(): ITextModel { + return this.model; + } + + public setModel(model: ITextModel = null): void { + if (this.model === model) { + // Current model is the new model + return; + } + + let detachedModel = this._detachModel(); + this._attachModel(model); + + let e: editorCommon.IModelChangedEvent = { + oldModelUrl: detachedModel ? detachedModel.uri : null, + newModelUrl: model ? model.uri : null + }; + + this._removeDecorationTypes(); + this._onDidChangeModel.fire(e); + this._postDetachModelCleanup(detachedModel); + } + + private _removeDecorationTypes(): void { + this._decorationTypeKeysToIds = {}; + if (this._decorationTypeSubtypes) { + for (let decorationType in this._decorationTypeSubtypes) { + let subTypes = this._decorationTypeSubtypes[decorationType]; + for (let subType in subTypes) { + this._removeDecorationType(decorationType + '-' + subType); + } + } + this._decorationTypeSubtypes = {}; + } + } + + public getVisibleRanges(): Range[] { + if (!this.hasView) { + return []; + } + return this.viewModel.getVisibleRanges(); + } + + public getWhitespaces(): IEditorWhitespace[] { + if (!this.hasView) { + return []; + } + return this.viewModel.viewLayout.getWhitespaces(); + } + + protected _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number { + let modelPosition = this.model.validatePosition({ + lineNumber: modelLineNumber, + column: modelColumn + }); + let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition); + return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber); + } + + public getTopForLineNumber(lineNumber: number): number { + if (!this.hasView) { + return -1; + } + return this._getVerticalOffsetForPosition(lineNumber, 1); + } + + public getTopForPosition(lineNumber: number, column: number): number { + if (!this.hasView) { + return -1; + } + return this._getVerticalOffsetForPosition(lineNumber, column); + } + + public setHiddenAreas(ranges: IRange[]): void { + if (this.viewModel) { + this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r))); + } + } + + public getVisibleColumnFromPosition(rawPosition: IPosition): number { + if (!this.model) { + return rawPosition.column; + } + + let position = this.model.validatePosition(rawPosition); + let tabSize = this.model.getOptions().tabSize; + + return CursorColumns.visibleColumnFromColumn(this.model.getLineContent(position.lineNumber), position.column, tabSize) + 1; + } + + public getPosition(): Position { + if (!this.cursor) { + return null; + } + return this.cursor.getPosition().clone(); + } + + public setPosition(position: IPosition): void { + if (!this.cursor) { + return; + } + if (!Position.isIPosition(position)) { + throw new Error('Invalid arguments'); + } + this.cursor.setSelections('api', [{ + selectionStartLineNumber: position.lineNumber, + selectionStartColumn: position.column, + positionLineNumber: position.lineNumber, + positionColumn: position.column + }]); + } + + private _sendRevealRange(modelRange: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { + if (!this.model || !this.cursor) { + return; + } + if (!Range.isIRange(modelRange)) { + throw new Error('Invalid arguments'); + } + const validatedModelRange = this.model.validateRange(modelRange); + const viewRange = this.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange); + + this.cursor.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); + } + + public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLine(lineNumber, VerticalRevealType.Simple, scrollType); + } + + public revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLine(lineNumber, VerticalRevealType.Center, scrollType); + } + + public revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLine(lineNumber, VerticalRevealType.CenterIfOutsideViewport, scrollType); + } + + private _revealLine(lineNumber: number, revealType: VerticalRevealType, scrollType: editorCommon.ScrollType): void { + if (typeof lineNumber !== 'number') { + throw new Error('Invalid arguments'); + } + + this._sendRevealRange( + new Range(lineNumber, 1, lineNumber, 1), + revealType, + false, + scrollType + ); + } + + public revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealPosition( + position, + VerticalRevealType.Simple, + true, + scrollType + ); + } + + public revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealPosition( + position, + VerticalRevealType.Center, + true, + scrollType + ); + } + + public revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealPosition( + position, + VerticalRevealType.CenterIfOutsideViewport, + true, + scrollType + ); + } + + private _revealPosition(position: IPosition, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { + if (!Position.isIPosition(position)) { + throw new Error('Invalid arguments'); + } + + this._sendRevealRange( + new Range(position.lineNumber, position.column, position.lineNumber, position.column), + verticalType, + revealHorizontal, + scrollType + ); + } + + public getSelection(): Selection { + if (!this.cursor) { + return null; + } + return this.cursor.getSelection().clone(); + } + + public getSelections(): Selection[] { + if (!this.cursor) { + return null; + } + let selections = this.cursor.getSelections(); + let result: Selection[] = []; + for (let i = 0, len = selections.length; i < len; i++) { + result[i] = selections[i].clone(); + } + return result; + } + + public setSelection(range: IRange): void; + public setSelection(editorRange: Range): void; + public setSelection(selection: ISelection): void; + public setSelection(editorSelection: Selection): void; + public setSelection(something: any): void { + let isSelection = Selection.isISelection(something); + let isRange = Range.isIRange(something); + + if (!isSelection && !isRange) { + throw new Error('Invalid arguments'); + } + + if (isSelection) { + this._setSelectionImpl(something); + } else if (isRange) { + // act as if it was an IRange + let selection: ISelection = { + selectionStartLineNumber: something.startLineNumber, + selectionStartColumn: something.startColumn, + positionLineNumber: something.endLineNumber, + positionColumn: something.endColumn + }; + this._setSelectionImpl(selection); + } + } + + private _setSelectionImpl(sel: ISelection): void { + if (!this.cursor) { + return; + } + let selection = new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn); + this.cursor.setSelections('api', [selection]); + } + + public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLines( + startLineNumber, + endLineNumber, + VerticalRevealType.Simple, + scrollType + ); + } + + public revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLines( + startLineNumber, + endLineNumber, + VerticalRevealType.Center, + scrollType + ); + } + + public revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealLines( + startLineNumber, + endLineNumber, + VerticalRevealType.CenterIfOutsideViewport, + scrollType + ); + } + + private _revealLines(startLineNumber: number, endLineNumber: number, verticalType: VerticalRevealType, scrollType: editorCommon.ScrollType): void { + if (typeof startLineNumber !== 'number' || typeof endLineNumber !== 'number') { + throw new Error('Invalid arguments'); + } + + this._sendRevealRange( + new Range(startLineNumber, 1, endLineNumber, 1), + verticalType, + false, + scrollType + ); + } + + public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void { + this._revealRange( + range, + revealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple, + revealHorizontal, + scrollType + ); + } + + public revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealRange( + range, + VerticalRevealType.Center, + true, + scrollType + ); + } + + public revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealRange( + range, + VerticalRevealType.CenterIfOutsideViewport, + true, + scrollType + ); + } + + public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { + this._revealRange( + range, + VerticalRevealType.Top, + true, + scrollType + ); + } + + private _revealRange(range: IRange, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { + if (!Range.isIRange(range)) { + throw new Error('Invalid arguments'); + } + + this._sendRevealRange( + Range.lift(range), + verticalType, + revealHorizontal, + scrollType + ); + } + + public setSelections(ranges: ISelection[]): void { + if (!this.cursor) { + return; + } + if (!ranges || ranges.length === 0) { + throw new Error('Invalid arguments'); + } + for (let i = 0, len = ranges.length; i < len; i++) { + if (!Selection.isISelection(ranges[i])) { + throw new Error('Invalid arguments'); + } + } + this.cursor.setSelections('api', ranges); + } + + public getScrollWidth(): number { + if (!this.hasView) { + return -1; + } + return this.viewModel.viewLayout.getScrollWidth(); + } + public getScrollLeft(): number { + if (!this.hasView) { + return -1; + } + return this.viewModel.viewLayout.getCurrentScrollLeft(); + } + + public getScrollHeight(): number { + if (!this.hasView) { + return -1; + } + return this.viewModel.viewLayout.getScrollHeight(); + } + public getScrollTop(): number { + if (!this.hasView) { + return -1; + } + return this.viewModel.viewLayout.getCurrentScrollTop(); + } + + public setScrollLeft(newScrollLeft: number): void { + if (!this.hasView) { + return; + } + if (typeof newScrollLeft !== 'number') { + throw new Error('Invalid arguments'); + } + this.viewModel.viewLayout.setScrollPositionNow({ + scrollLeft: newScrollLeft + }); + } + public setScrollTop(newScrollTop: number): void { + if (!this.hasView) { + return; + } + if (typeof newScrollTop !== 'number') { + throw new Error('Invalid arguments'); + } + this.viewModel.viewLayout.setScrollPositionNow({ + scrollTop: newScrollTop + }); + } + public setScrollPosition(position: editorCommon.INewScrollPosition): void { + if (!this.hasView) { + return; + } + this.viewModel.viewLayout.setScrollPositionNow(position); + } + + public saveViewState(): editorCommon.ICodeEditorViewState { + if (!this.cursor || !this.hasView) { + return null; + } + const contributionsState: { [key: string]: any } = {}; + + const keys = Object.keys(this._contributions); + for (let i = 0, len = keys.length; i < len; i++) { + const id = keys[i]; + const contribution = this._contributions[id]; + if (typeof contribution.saveViewState === 'function') { + contributionsState[id] = contribution.saveViewState(); + } + } + + const cursorState = this.cursor.saveState(); + const viewState = this.viewModel.saveState(); + return { + cursorState: cursorState, + viewState: viewState, + contributionsState: contributionsState + }; + } + + public restoreViewState(s: editorCommon.ICodeEditorViewState): void { + if (!this.cursor || !this.hasView) { + return; + } + if (s && s.cursorState && s.viewState) { + let codeEditorState = s; + let cursorState = codeEditorState.cursorState; + if (Array.isArray(cursorState)) { + this.cursor.restoreState(cursorState); + } else { + // Backwards compatibility + this.cursor.restoreState([cursorState]); + } + + let contributionsState = s.contributionsState || {}; + let keys = Object.keys(this._contributions); + for (let i = 0, len = keys.length; i < len; i++) { + let id = keys[i]; + let contribution = this._contributions[id]; + if (typeof contribution.restoreViewState === 'function') { + contribution.restoreViewState(contributionsState[id]); + } + } + + const reducedState = this.viewModel.reduceRestoreState(s.viewState); + const linesViewportData = this.viewModel.viewLayout.getLinesViewportDataAtScrollTop(reducedState.scrollTop); + const startPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1)); + const endPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.endLineNumber, 1)); + this.model.tokenizeViewport(startPosition.lineNumber, endPosition.lineNumber); + this._view.restoreState(reducedState); + } + } + + public onVisible(): void { + } + + public onHide(): void { + } + + public getContribution(id: string): T { + return (this._contributions[id] || null); + } + + public getActions(): editorCommon.IEditorAction[] { + let result: editorCommon.IEditorAction[] = []; + + let keys = Object.keys(this._actions); + for (let i = 0, len = keys.length; i < len; i++) { + let id = keys[i]; + result.push(this._actions[id]); + } + + return result; + } + + public getSupportedActions(): editorCommon.IEditorAction[] { + let result = this.getActions(); + + result = result.filter(action => action.isSupported()); + + return result; + } + + public getAction(id: string): editorCommon.IEditorAction { + return this._actions[id] || null; + } + + public trigger(source: string, handlerId: string, payload: any): void { + payload = payload || {}; + + // Special case for typing + if (handlerId === editorCommon.Handler.Type) { + if (!this.cursor || typeof payload.text !== 'string' || payload.text.length === 0) { + // nothing to do + return; + } + if (source === 'keyboard') { + this._onWillType.fire(payload.text); + } + this.cursor.trigger(source, handlerId, payload); + if (source === 'keyboard') { + this._onDidType.fire(payload.text); + } + return; + } + + // Special case for pasting + if (handlerId === editorCommon.Handler.Paste) { + if (!this.cursor || typeof payload.text !== 'string' || payload.text.length === 0) { + // nothing to do + return; + } + const startPosition = this.cursor.getSelection().getStartPosition(); + this.cursor.trigger(source, handlerId, payload); + const endPosition = this.cursor.getSelection().getStartPosition(); + if (source === 'keyboard') { + this._onDidPaste.fire( + new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column) + ); + } + return; + } + + const action = this.getAction(handlerId); + if (action) { + TPromise.as(action.run()).then(null, onUnexpectedError); + return; + } + + if (!this.cursor) { + return; + } + + if (this._triggerEditorCommand(source, handlerId, payload)) { + return; + } + + this.cursor.trigger(source, handlerId, payload); + } + + private _triggerEditorCommand(source: string, handlerId: string, payload: any): boolean { + const command = EditorExtensionsRegistry.getEditorCommand(handlerId); + if (command) { + payload = payload || {}; + payload.source = source; + TPromise.as(command.runEditorCommand(null, this, payload)).done(null, onUnexpectedError); + return true; + } + + return false; + } + + public _getCursors(): ICursors { + return this.cursor; + } + + public _getCursorConfiguration(): CursorConfiguration { + return this.cursor.context.config; + } + + public pushUndoStop(): boolean { + if (!this.model) { + return false; + } + if (this._configuration.editor.readOnly) { + // read only editor => sorry! + return false; + } + this.model.pushStackElement(); + return true; + } + + public executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursorState?: Selection[]): boolean { + if (!this.cursor) { + // no view, no cursor + return false; + } + if (this._configuration.editor.readOnly) { + // read only editor => sorry! + return false; + } + + this.model.pushEditOperations(this.cursor.getSelections(), edits, () => { + return endCursorState ? endCursorState : null; + }); + + if (endCursorState) { + this.cursor.setSelections(source, endCursorState); + } + + return true; + } + + public executeCommand(source: string, command: editorCommon.ICommand): void { + if (!this.cursor) { + return; + } + this.cursor.trigger(source, editorCommon.Handler.ExecuteCommand, command); + } + + public executeCommands(source: string, commands: editorCommon.ICommand[]): void { + if (!this.cursor) { + return; + } + this.cursor.trigger(source, editorCommon.Handler.ExecuteCommands, commands); + } + + public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any { + if (!this.model) { + // console.warn('Cannot change decorations on editor that is not attached to a model'); + // callback will not be called + return null; + } + return this.model.changeDecorations(callback, this.id); + } + + public getLineDecorations(lineNumber: number): IModelDecoration[] { + if (!this.model) { + return null; + } + return this.model.getLineDecorations(lineNumber, this.id, this._configuration.editor.readOnly); + } + + public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] { + if (!this.model) { + return []; + } + + if (oldDecorations.length === 0 && newDecorations.length === 0) { + return oldDecorations; + } + + return this.model.deltaDecorations(oldDecorations, newDecorations, this.id); + } + + public setDecorations(decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void { + + let newDecorationsSubTypes: { [key: string]: boolean } = {}; + let oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; + this._decorationTypeSubtypes[decorationTypeKey] = newDecorationsSubTypes; + + let newModelDecorations: IModelDeltaDecoration[] = []; + + for (let decorationOption of decorationOptions) { + let typeKey = decorationTypeKey; + if (decorationOption.renderOptions) { + // identify custom reder options by a hash code over all keys and values + // For custom render options register a decoration type if necessary + let subType = hash(decorationOption.renderOptions).toString(16); + // The fact that `decorationTypeKey` appears in the typeKey has no influence + // it is just a mechanism to get predictable and unique keys (repeatable for the same options and unique across clients) + typeKey = decorationTypeKey + '-' + subType; + if (!oldDecorationsSubTypes[subType] && !newDecorationsSubTypes[subType]) { + // decoration type did not exist before, register new one + this._registerDecorationType(typeKey, decorationOption.renderOptions, decorationTypeKey); + } + newDecorationsSubTypes[subType] = true; + } + let opts = this._resolveDecorationOptions(typeKey, !!decorationOption.hoverMessage); + if (decorationOption.hoverMessage) { + opts.hoverMessage = decorationOption.hoverMessage; + } + newModelDecorations.push({ range: decorationOption.range, options: opts }); + } + + // remove decoration sub types that are no longer used, deregister decoration type if necessary + for (let subType in oldDecorationsSubTypes) { + if (!newDecorationsSubTypes[subType]) { + this._removeDecorationType(decorationTypeKey + '-' + subType); + } + } + + // update all decorations + let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || []; + this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); + } + + public setDecorationsFast(decorationTypeKey: string, ranges: IRange[]): void { + + // remove decoration sub types that are no longer used, deregister decoration type if necessary + let oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; + for (let subType in oldDecorationsSubTypes) { + this._removeDecorationType(decorationTypeKey + '-' + subType); + } + this._decorationTypeSubtypes[decorationTypeKey] = {}; + + const opts = ModelDecorationOptions.createDynamic(this._resolveDecorationOptions(decorationTypeKey, false)); + let newModelDecorations: IModelDeltaDecoration[] = new Array(ranges.length); + for (let i = 0, len = ranges.length; i < len; i++) { + newModelDecorations[i] = { range: ranges[i], options: opts }; + } + + // update all decorations + let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || []; + this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); + } + + public removeDecorations(decorationTypeKey: string): void { + // remove decorations for type and sub type + let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey]; + if (oldDecorationsIds) { + this.deltaDecorations(oldDecorationsIds, []); + } + if (this._decorationTypeKeysToIds.hasOwnProperty(decorationTypeKey)) { + delete this._decorationTypeKeysToIds[decorationTypeKey]; + } + if (this._decorationTypeSubtypes.hasOwnProperty(decorationTypeKey)) { + delete this._decorationTypeSubtypes[decorationTypeKey]; + } + } + + public getLayoutInfo(): editorOptions.EditorLayoutInfo { + return this._configuration.editor.layoutInfo; + } + public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler { return this._view.createOverviewRuler(cssClassName); } @@ -325,10 +1226,80 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo); } - _attachModel(model: ITextModel): void { + protected _attachModel(model: ITextModel): void { this._view = null; - super._attachModel(model); + this.model = model ? model : null; + this.listenersToRemove = []; + this.viewModel = null; + this.cursor = null; + + if (this.model) { + this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language); + this._configuration.setIsDominatedByLongLines(this.model.isDominatedByLongLines()); + this._configuration.setMaxLineNumber(this.model.getLineCount()); + + this.model.onBeforeAttached(); + + this.viewModel = new ViewModel(this.id, this._configuration, this.model, (callback) => dom.scheduleAtNextAnimationFrame(callback)); + + this.listenersToRemove.push(this.model.onDidChangeDecorations((e) => this._onDidChangeModelDecorations.fire(e))); + this.listenersToRemove.push(this.model.onDidChangeLanguage((e) => { + if (!this.model) { + return; + } + this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language); + this._onDidChangeModelLanguage.fire(e); + })); + this.listenersToRemove.push(this.model.onDidChangeLanguageConfiguration((e) => this._onDidChangeModelLanguageConfiguration.fire(e))); + this.listenersToRemove.push(this.model.onDidChangeContent((e) => this._onDidChangeModelContent.fire(e))); + this.listenersToRemove.push(this.model.onDidChangeOptions((e) => this._onDidChangeModelOptions.fire(e))); + // Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model + this.listenersToRemove.push(this.model.onWillDispose(() => this.setModel(null))); + + this.cursor = new Cursor( + this._configuration, + this.model, + this.viewModel + ); + + this._createView(); + + this.listenersToRemove.push(this.cursor.onDidReachMaxCursorCount(() => { + this._notificationService.warn(nls.localize('cursors.maximum', "The number of cursors has been limited to {0}.", Cursor.MAX_CURSOR_COUNT)); + })); + + this.listenersToRemove.push(this.cursor.onDidAttemptReadOnlyEdit(() => { + this._onDidAttemptReadOnlyEdit.fire(void 0); + })); + + this.listenersToRemove.push(this.cursor.onDidChange((e: CursorStateChangedEvent) => { + + let positions: Position[] = []; + for (let i = 0, len = e.selections.length; i < len; i++) { + positions[i] = e.selections[i].getPosition(); + } + + const e1: ICursorPositionChangedEvent = { + position: positions[0], + secondaryPositions: positions.slice(1), + reason: e.reason, + source: e.source + }; + this._onDidChangeCursorPosition.fire(e1); + + const e2: ICursorSelectionChangedEvent = { + selection: e.selections[0], + secondarySelections: e.selections.slice(1), + source: e.source, + reason: e.reason + }; + this._onDidChangeCursorSelection.fire(e2); + })); + + } else { + this.hasView = false; + } if (this._view) { this.domElement.appendChild(this._view.domNode.domNode); @@ -351,10 +1322,6 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito } } - protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable { - return dom.scheduleAtNextAnimationFrame(callback); - } - protected _createView(): void { let commandDelegate: ICommandDelegate; if (this.isSimpleWidget) { @@ -445,18 +1412,9 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito viewEventBus.onKeyDown = (e) => this._onKeyDown.fire(e); } - public restoreViewState(s: editorCommon.ICodeEditorViewState): void { - super.restoreViewState(s); - if (!this.cursor || !this.hasView) { - return; - } - if (s && s.cursorState && s.viewState) { - const reducedState = this.viewModel.reduceRestoreState(s.viewState); - const linesViewportData = this.viewModel.viewLayout.getLinesViewportDataAtScrollTop(reducedState.scrollTop); - const startPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1)); - const endPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.endLineNumber, 1)); - this.model.tokenizeViewport(startPosition.lineNumber, endPosition.lineNumber); - this._view.restoreState(reducedState); + protected _postDetachModelCleanup(detachedModel: ITextModel): void { + if (detachedModel) { + detachedModel.removeAllDecorationsWithOwnerId(this.id); } } @@ -469,7 +1427,28 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito this._view = null; } - let result = super._detachModel(); + if (this.model) { + this.model.onBeforeDetached(); + } + + this.hasView = false; + + this.listenersToRemove = dispose(this.listenersToRemove); + + if (this.cursor) { + this.cursor.dispose(); + this.cursor = null; + } + + if (this.viewModel) { + this.viewModel.dispose(); + this.viewModel = null; + } + + let result = this.model; + this.model = null; + + this.domElement.removeAttribute('data-mode-id'); if (removeDomNode) { this.domElement.removeChild(removeDomNode); @@ -478,32 +1457,240 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito return result; } - // BEGIN decorations - - protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void { + private _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void { this._codeEditorService.registerDecorationType(key, options, parentTypeKey); } - protected _removeDecorationType(key: string): void { + private _removeDecorationType(key: string): void { this._codeEditorService.removeDecorationType(key); } - protected _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions { + private _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions { return this._codeEditorService.resolveDecorationOptions(typeKey, writable); } - // END decorations + /* __GDPR__FRAGMENT__ + "EditorTelemetryData" : {} + */ + public getTelemetryData(): { [key: string]: any; } { + return null; + } +} - protected _triggerEditorCommand(source: string, handlerId: string, payload: any): boolean { - const command = EditorExtensionsRegistry.getEditorCommand(handlerId); - if (command) { - payload = payload || {}; - payload.source = source; - TPromise.as(command.runEditorCommand(null, this, payload)).done(null, onUnexpectedError); - return true; +const enum BooleanEventValue { + NotSet, + False, + True +} + +export class BooleanEventEmitter extends Disposable { + private readonly _onDidChangeToTrue: Emitter = this._register(new Emitter()); + public readonly onDidChangeToTrue: Event = this._onDidChangeToTrue.event; + + private readonly _onDidChangeToFalse: Emitter = this._register(new Emitter()); + public readonly onDidChangeToFalse: Event = this._onDidChangeToFalse.event; + + private _value: BooleanEventValue; + + constructor() { + super(); + this._value = BooleanEventValue.NotSet; + } + + public setValue(_value: boolean) { + let value = (_value ? BooleanEventValue.True : BooleanEventValue.False); + if (this._value === value) { + return; } + this._value = value; + if (this._value === BooleanEventValue.True) { + this._onDidChangeToTrue.fire(); + } else if (this._value === BooleanEventValue.False) { + this._onDidChangeToFalse.fire(); + } + } +} - return false; +class EditorContextKeysManager extends Disposable { + + private _editor: CodeEditorWidget; + private _editorFocus: IContextKey; + private _textInputFocus: IContextKey; + private _editorTextFocus: IContextKey; + private _editorTabMovesFocus: IContextKey; + private _editorReadonly: IContextKey; + private _hasMultipleSelections: IContextKey; + private _hasNonEmptySelection: IContextKey; + + constructor( + editor: CodeEditorWidget, + contextKeyService: IContextKeyService + ) { + super(); + + this._editor = editor; + + contextKeyService.createKey('editorId', editor.getId()); + this._editorFocus = EditorContextKeys.focus.bindTo(contextKeyService); + this._textInputFocus = EditorContextKeys.textInputFocus.bindTo(contextKeyService); + this._editorTextFocus = EditorContextKeys.editorTextFocus.bindTo(contextKeyService); + this._editorTabMovesFocus = EditorContextKeys.tabMovesFocus.bindTo(contextKeyService); + this._editorReadonly = EditorContextKeys.readOnly.bindTo(contextKeyService); + this._hasMultipleSelections = EditorContextKeys.hasMultipleSelections.bindTo(contextKeyService); + this._hasNonEmptySelection = EditorContextKeys.hasNonEmptySelection.bindTo(contextKeyService); + + this._register(this._editor.onDidChangeConfiguration(() => this._updateFromConfig())); + this._register(this._editor.onDidChangeCursorSelection(() => this._updateFromSelection())); + this._register(this._editor.onDidFocusEditor(() => this._updateFromFocus())); + this._register(this._editor.onDidBlurEditor(() => this._updateFromFocus())); + this._register(this._editor.onDidFocusEditorText(() => this._updateFromFocus())); + this._register(this._editor.onDidBlurEditorText(() => this._updateFromFocus())); + + this._updateFromConfig(); + this._updateFromSelection(); + this._updateFromFocus(); + } + + private _updateFromConfig(): void { + let config = this._editor.getConfiguration(); + + this._editorTabMovesFocus.set(config.tabFocusMode); + this._editorReadonly.set(config.readOnly); + } + + private _updateFromSelection(): void { + let selections = this._editor.getSelections(); + if (!selections) { + this._hasMultipleSelections.reset(); + this._hasNonEmptySelection.reset(); + } else { + this._hasMultipleSelections.set(selections.length > 1); + this._hasNonEmptySelection.set(selections.some(s => !s.isEmpty())); + } + } + + private _updateFromFocus(): void { + this._editorFocus.set(this._editor.hasWidgetFocus() && !this._editor.isSimpleWidget); + this._editorTextFocus.set(this._editor.isFocused() && !this._editor.isSimpleWidget); + this._textInputFocus.set(this._editor.isFocused()); + } +} + +export class EditorModeContext extends Disposable { + + private _editor: CodeEditorWidget; + + private _langId: IContextKey; + private _hasCompletionItemProvider: IContextKey; + private _hasCodeActionsProvider: IContextKey; + private _hasCodeLensProvider: IContextKey; + private _hasDefinitionProvider: IContextKey; + private _hasImplementationProvider: IContextKey; + private _hasTypeDefinitionProvider: IContextKey; + private _hasHoverProvider: IContextKey; + private _hasDocumentHighlightProvider: IContextKey; + private _hasDocumentSymbolProvider: IContextKey; + private _hasReferenceProvider: IContextKey; + private _hasRenameProvider: IContextKey; + private _hasDocumentFormattingProvider: IContextKey; + private _hasDocumentSelectionFormattingProvider: IContextKey; + private _hasSignatureHelpProvider: IContextKey; + private _isInWalkThrough: IContextKey; + + constructor( + editor: CodeEditorWidget, + contextKeyService: IContextKeyService + ) { + super(); + this._editor = editor; + + this._langId = EditorContextKeys.languageId.bindTo(contextKeyService); + this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService); + this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); + this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService); + this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(contextKeyService); + this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(contextKeyService); + this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService); + this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(contextKeyService); + this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService); + this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService); + this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService); + this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService); + this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService); + this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService); + this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService); + this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService); + + const update = () => this._update(); + + // update when model/mode changes + this._register(editor.onDidChangeModel(update)); + this._register(editor.onDidChangeModelLanguage(update)); + + // update when registries change + this._register(modes.SuggestRegistry.onDidChange(update)); + this._register(modes.CodeActionProviderRegistry.onDidChange(update)); + this._register(modes.CodeLensProviderRegistry.onDidChange(update)); + this._register(modes.DefinitionProviderRegistry.onDidChange(update)); + this._register(modes.ImplementationProviderRegistry.onDidChange(update)); + this._register(modes.TypeDefinitionProviderRegistry.onDidChange(update)); + this._register(modes.HoverProviderRegistry.onDidChange(update)); + this._register(modes.DocumentHighlightProviderRegistry.onDidChange(update)); + this._register(modes.DocumentSymbolProviderRegistry.onDidChange(update)); + this._register(modes.ReferenceProviderRegistry.onDidChange(update)); + this._register(modes.RenameProviderRegistry.onDidChange(update)); + this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update)); + this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update)); + this._register(modes.SignatureHelpProviderRegistry.onDidChange(update)); + + update(); + } + + dispose() { + super.dispose(); + } + + reset() { + this._langId.reset(); + this._hasCompletionItemProvider.reset(); + this._hasCodeActionsProvider.reset(); + this._hasCodeLensProvider.reset(); + this._hasDefinitionProvider.reset(); + this._hasImplementationProvider.reset(); + this._hasTypeDefinitionProvider.reset(); + this._hasHoverProvider.reset(); + this._hasDocumentHighlightProvider.reset(); + this._hasDocumentSymbolProvider.reset(); + this._hasReferenceProvider.reset(); + this._hasRenameProvider.reset(); + this._hasDocumentFormattingProvider.reset(); + this._hasDocumentSelectionFormattingProvider.reset(); + this._hasSignatureHelpProvider.reset(); + this._isInWalkThrough.reset(); + } + + private _update() { + const model = this._editor.getModel(); + if (!model) { + this.reset(); + return; + } + this._langId.set(model.getLanguageIdentifier().language); + this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model)); + this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); + this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); + this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model)); + this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model)); + this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model)); + this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model)); + this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model)); + this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model)); + this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model)); + this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model)); + this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model)); + this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model)); + this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model)); + this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet); } } diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts deleted file mode 100644 index 99b0be6b3aa..00000000000 --- a/src/vs/editor/common/commonCodeEditor.ts +++ /dev/null @@ -1,1270 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as nls from 'vs/nls'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IContextKey, IContextKeyServiceTarget, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor'; -import { CursorColumns, ICursors, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon'; -import { Position, IPosition } from 'vs/editor/common/core/position'; -import { Range, IRange } from 'vs/editor/common/core/range'; -import { Selection, ISelection } from 'vs/editor/common/core/selection'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; -import { hash } from 'vs/base/common/hash'; -import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; -import * as editorOptions from 'vs/editor/common/config/editorOptions'; -import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; -import * as modes from 'vs/editor/common/modes'; -import { Schemas } from 'vs/base/common/network'; -import { ITextModel, EndOfLinePreference, IIdentifiedSingleEditOperation, IModelDecorationsChangeAccessor, IModelDecoration, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model'; -import { INotificationService } from 'vs/platform/notification/common/notification'; - -let EDITOR_ID = 0; - -export abstract class CommonCodeEditor extends Disposable { - - private readonly _onDidDispose: Emitter = this._register(new Emitter()); - public readonly onDidDispose: Event = this._onDidDispose.event; - - private readonly _onDidChangeModelContent: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelContent: Event = this._onDidChangeModelContent.event; - - private readonly _onDidChangeModelLanguage: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event; - - private readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguageConfiguration.event; - - private readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event; - - private readonly _onDidChangeModelDecorations: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelDecorations: Event = this._onDidChangeModelDecorations.event; - - private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; - - protected readonly _onDidChangeModel: Emitter = this._register(new Emitter()); - public readonly onDidChangeModel: Event = this._onDidChangeModel.event; - - private readonly _onDidChangeCursorPosition: Emitter = this._register(new Emitter()); - public readonly onDidChangeCursorPosition: Event = this._onDidChangeCursorPosition.event; - - private readonly _onDidChangeCursorSelection: Emitter = this._register(new Emitter()); - public readonly onDidChangeCursorSelection: Event = this._onDidChangeCursorSelection.event; - - private readonly _onDidAttemptReadOnlyEdit: Emitter = this._register(new Emitter()); - public readonly onDidAttemptReadOnlyEdit: Event = this._onDidAttemptReadOnlyEdit.event; - - private readonly _onDidLayoutChange: Emitter = this._register(new Emitter()); - public readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; - - protected _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); - public readonly onDidFocusEditorText: Event = this._editorTextFocus.onDidChangeToTrue; - public readonly onDidBlurEditorText: Event = this._editorTextFocus.onDidChangeToFalse; - - protected _editorFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter()); - public readonly onDidFocusEditor: Event = this._editorFocus.onDidChangeToTrue; - public readonly onDidBlurEditor: Event = this._editorFocus.onDidChangeToFalse; - - private readonly _onWillType: Emitter = this._register(new Emitter()); - public readonly onWillType = this._onWillType.event; - - private readonly _onDidType: Emitter = this._register(new Emitter()); - public readonly onDidType = this._onDidType.event; - - private readonly _onDidPaste: Emitter = this._register(new Emitter()); - public readonly onDidPaste = this._onDidPaste.event; - - public readonly isSimpleWidget: boolean; - - protected readonly domElement: IContextKeyServiceTarget; - protected readonly id: number; - protected readonly _configuration: CommonEditorConfiguration; - - protected _contributions: { [key: string]: editorCommon.IEditorContribution; }; - protected _actions: { [key: string]: editorCommon.IEditorAction; }; - - // --- Members logically associated to a model - protected model: ITextModel; - protected listenersToRemove: IDisposable[]; - protected hasView: boolean; - - protected viewModel: ViewModel; - protected cursor: Cursor; - - protected readonly _instantiationService: IInstantiationService; - protected readonly _contextKeyService: IContextKeyService; - protected readonly _notificationService: INotificationService; - - /** - * map from "parent" decoration type to live decoration ids. - */ - private _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] }; - private _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } }; - - - constructor( - domElement: IContextKeyServiceTarget, - options: editorOptions.IEditorOptions, - isSimpleWidget: boolean, - instantiationService: IInstantiationService, - contextKeyService: IContextKeyService, - notificationService: INotificationService, - ) { - super(); - this.domElement = domElement; - this.id = (++EDITOR_ID); - this._decorationTypeKeysToIds = {}; - this._decorationTypeSubtypes = {}; - this.isSimpleWidget = isSimpleWidget; - - options = options || {}; - this._configuration = this._register(this._createConfiguration(options)); - this._register(this._configuration.onDidChange((e) => { - this._onDidChangeConfiguration.fire(e); - - if (e.layoutInfo) { - this._onDidLayoutChange.fire(this._configuration.editor.layoutInfo); - } - })); - - this._contextKeyService = this._register(contextKeyService.createScoped(this.domElement)); - this._notificationService = notificationService; - this._register(new EditorContextKeysManager(this, this._contextKeyService)); - this._register(new EditorModeContext(this, this._contextKeyService)); - - this._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])); - - this._attachModel(null); - - this._contributions = {}; - this._actions = {}; - } - - protected abstract _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration; - - public getId(): string { - return this.getEditorType() + ':' + this.id; - } - - public getEditorType(): string { - return editorCommon.EditorType.ICodeEditor; - } - - public dispose(): void { - let keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - let contributionId = keys[i]; - this._contributions[contributionId].dispose(); - } - this._contributions = {}; - - // editor actions don't need to be disposed - this._actions = {}; - this._removeDecorationTypes(); - this._postDetachModelCleanup(this._detachModel()); - - this._onDidDispose.fire(); - - super.dispose(); - } - - public invokeWithinContext(fn: (accessor: ServicesAccessor) => T): T { - return this._instantiationService.invokeFunction(fn); - } - - public updateOptions(newOptions: editorOptions.IEditorOptions): void { - this._configuration.updateOptions(newOptions); - } - - public getConfiguration(): editorOptions.InternalEditorOptions { - return this._configuration.editor; - } - - public getRawConfiguration(): editorOptions.IEditorOptions { - return this._configuration.getRawOptions(); - } - - public getValue(options: { preserveBOM: boolean; lineEnding: string; } = null): string { - if (this.model) { - let preserveBOM: boolean = (options && options.preserveBOM) ? true : false; - let eolPreference = EndOfLinePreference.TextDefined; - if (options && options.lineEnding && options.lineEnding === '\n') { - eolPreference = EndOfLinePreference.LF; - } else if (options && options.lineEnding && options.lineEnding === '\r\n') { - eolPreference = EndOfLinePreference.CRLF; - } - return this.model.getValue(eolPreference, preserveBOM); - } - return ''; - } - - public setValue(newValue: string): void { - if (this.model) { - this.model.setValue(newValue); - } - } - - public getModel(): ITextModel { - return this.model; - } - - public setModel(model: ITextModel = null): void { - if (this.model === model) { - // Current model is the new model - return; - } - - let detachedModel = this._detachModel(); - this._attachModel(model); - - let e: editorCommon.IModelChangedEvent = { - oldModelUrl: detachedModel ? detachedModel.uri : null, - newModelUrl: model ? model.uri : null - }; - - this._removeDecorationTypes(); - this._onDidChangeModel.fire(e); - this._postDetachModelCleanup(detachedModel); - } - - private _removeDecorationTypes(): void { - this._decorationTypeKeysToIds = {}; - if (this._decorationTypeSubtypes) { - for (let decorationType in this._decorationTypeSubtypes) { - let subTypes = this._decorationTypeSubtypes[decorationType]; - for (let subType in subTypes) { - this._removeDecorationType(decorationType + '-' + subType); - } - } - this._decorationTypeSubtypes = {}; - } - } - - public getVisibleRanges(): Range[] { - if (!this.hasView) { - return []; - } - return this.viewModel.getVisibleRanges(); - } - - public getWhitespaces(): IEditorWhitespace[] { - if (!this.hasView) { - return []; - } - return this.viewModel.viewLayout.getWhitespaces(); - } - - protected _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number { - let modelPosition = this.model.validatePosition({ - lineNumber: modelLineNumber, - column: modelColumn - }); - let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition); - return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber); - } - - public getTopForLineNumber(lineNumber: number): number { - if (!this.hasView) { - return -1; - } - return this._getVerticalOffsetForPosition(lineNumber, 1); - } - - public getTopForPosition(lineNumber: number, column: number): number { - if (!this.hasView) { - return -1; - } - return this._getVerticalOffsetForPosition(lineNumber, column); - } - - public setHiddenAreas(ranges: IRange[]): void { - if (this.viewModel) { - this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r))); - } - } - - public getVisibleColumnFromPosition(rawPosition: IPosition): number { - if (!this.model) { - return rawPosition.column; - } - - let position = this.model.validatePosition(rawPosition); - let tabSize = this.model.getOptions().tabSize; - - return CursorColumns.visibleColumnFromColumn(this.model.getLineContent(position.lineNumber), position.column, tabSize) + 1; - } - - public getPosition(): Position { - if (!this.cursor) { - return null; - } - return this.cursor.getPosition().clone(); - } - - public setPosition(position: IPosition): void { - if (!this.cursor) { - return; - } - if (!Position.isIPosition(position)) { - throw new Error('Invalid arguments'); - } - this.cursor.setSelections('api', [{ - selectionStartLineNumber: position.lineNumber, - selectionStartColumn: position.column, - positionLineNumber: position.lineNumber, - positionColumn: position.column - }]); - } - - private _sendRevealRange(modelRange: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { - if (!this.model || !this.cursor) { - return; - } - if (!Range.isIRange(modelRange)) { - throw new Error('Invalid arguments'); - } - const validatedModelRange = this.model.validateRange(modelRange); - const viewRange = this.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange); - - this.cursor.emitCursorRevealRange(viewRange, verticalType, revealHorizontal, scrollType); - } - - public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLine(lineNumber, VerticalRevealType.Simple, scrollType); - } - - public revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLine(lineNumber, VerticalRevealType.Center, scrollType); - } - - public revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLine(lineNumber, VerticalRevealType.CenterIfOutsideViewport, scrollType); - } - - private _revealLine(lineNumber: number, revealType: VerticalRevealType, scrollType: editorCommon.ScrollType): void { - if (typeof lineNumber !== 'number') { - throw new Error('Invalid arguments'); - } - - this._sendRevealRange( - new Range(lineNumber, 1, lineNumber, 1), - revealType, - false, - scrollType - ); - } - - public revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealPosition( - position, - VerticalRevealType.Simple, - true, - scrollType - ); - } - - public revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealPosition( - position, - VerticalRevealType.Center, - true, - scrollType - ); - } - - public revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealPosition( - position, - VerticalRevealType.CenterIfOutsideViewport, - true, - scrollType - ); - } - - private _revealPosition(position: IPosition, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { - if (!Position.isIPosition(position)) { - throw new Error('Invalid arguments'); - } - - this._sendRevealRange( - new Range(position.lineNumber, position.column, position.lineNumber, position.column), - verticalType, - revealHorizontal, - scrollType - ); - } - - public getSelection(): Selection { - if (!this.cursor) { - return null; - } - return this.cursor.getSelection().clone(); - } - - public getSelections(): Selection[] { - if (!this.cursor) { - return null; - } - let selections = this.cursor.getSelections(); - let result: Selection[] = []; - for (let i = 0, len = selections.length; i < len; i++) { - result[i] = selections[i].clone(); - } - return result; - } - - public setSelection(range: IRange): void; - public setSelection(editorRange: Range): void; - public setSelection(selection: ISelection): void; - public setSelection(editorSelection: Selection): void; - public setSelection(something: any): void { - let isSelection = Selection.isISelection(something); - let isRange = Range.isIRange(something); - - if (!isSelection && !isRange) { - throw new Error('Invalid arguments'); - } - - if (isSelection) { - this._setSelectionImpl(something); - } else if (isRange) { - // act as if it was an IRange - let selection: ISelection = { - selectionStartLineNumber: something.startLineNumber, - selectionStartColumn: something.startColumn, - positionLineNumber: something.endLineNumber, - positionColumn: something.endColumn - }; - this._setSelectionImpl(selection); - } - } - - private _setSelectionImpl(sel: ISelection): void { - if (!this.cursor) { - return; - } - let selection = new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn); - this.cursor.setSelections('api', [selection]); - } - - public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLines( - startLineNumber, - endLineNumber, - VerticalRevealType.Simple, - scrollType - ); - } - - public revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLines( - startLineNumber, - endLineNumber, - VerticalRevealType.Center, - scrollType - ); - } - - public revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealLines( - startLineNumber, - endLineNumber, - VerticalRevealType.CenterIfOutsideViewport, - scrollType - ); - } - - private _revealLines(startLineNumber: number, endLineNumber: number, verticalType: VerticalRevealType, scrollType: editorCommon.ScrollType): void { - if (typeof startLineNumber !== 'number' || typeof endLineNumber !== 'number') { - throw new Error('Invalid arguments'); - } - - this._sendRevealRange( - new Range(startLineNumber, 1, endLineNumber, 1), - verticalType, - false, - scrollType - ); - } - - public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void { - this._revealRange( - range, - revealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple, - revealHorizontal, - scrollType - ); - } - - public revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealRange( - range, - VerticalRevealType.Center, - true, - scrollType - ); - } - - public revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealRange( - range, - VerticalRevealType.CenterIfOutsideViewport, - true, - scrollType - ); - } - - public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void { - this._revealRange( - range, - VerticalRevealType.Top, - true, - scrollType - ); - } - - private _revealRange(range: IRange, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void { - if (!Range.isIRange(range)) { - throw new Error('Invalid arguments'); - } - - this._sendRevealRange( - Range.lift(range), - verticalType, - revealHorizontal, - scrollType - ); - } - - public setSelections(ranges: ISelection[]): void { - if (!this.cursor) { - return; - } - if (!ranges || ranges.length === 0) { - throw new Error('Invalid arguments'); - } - for (let i = 0, len = ranges.length; i < len; i++) { - if (!Selection.isISelection(ranges[i])) { - throw new Error('Invalid arguments'); - } - } - this.cursor.setSelections('api', ranges); - } - - public getScrollWidth(): number { - if (!this.hasView) { - return -1; - } - return this.viewModel.viewLayout.getScrollWidth(); - } - public getScrollLeft(): number { - if (!this.hasView) { - return -1; - } - return this.viewModel.viewLayout.getCurrentScrollLeft(); - } - - public getScrollHeight(): number { - if (!this.hasView) { - return -1; - } - return this.viewModel.viewLayout.getScrollHeight(); - } - public getScrollTop(): number { - if (!this.hasView) { - return -1; - } - return this.viewModel.viewLayout.getCurrentScrollTop(); - } - - public setScrollLeft(newScrollLeft: number): void { - if (!this.hasView) { - return; - } - if (typeof newScrollLeft !== 'number') { - throw new Error('Invalid arguments'); - } - this.viewModel.viewLayout.setScrollPositionNow({ - scrollLeft: newScrollLeft - }); - } - public setScrollTop(newScrollTop: number): void { - if (!this.hasView) { - return; - } - if (typeof newScrollTop !== 'number') { - throw new Error('Invalid arguments'); - } - this.viewModel.viewLayout.setScrollPositionNow({ - scrollTop: newScrollTop - }); - } - public setScrollPosition(position: editorCommon.INewScrollPosition): void { - if (!this.hasView) { - return; - } - this.viewModel.viewLayout.setScrollPositionNow(position); - } - - public saveViewState(): editorCommon.ICodeEditorViewState { - if (!this.cursor || !this.hasView) { - return null; - } - const contributionsState: { [key: string]: any } = {}; - - const keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - const id = keys[i]; - const contribution = this._contributions[id]; - if (typeof contribution.saveViewState === 'function') { - contributionsState[id] = contribution.saveViewState(); - } - } - - const cursorState = this.cursor.saveState(); - const viewState = this.viewModel.saveState(); - return { - cursorState: cursorState, - viewState: viewState, - contributionsState: contributionsState - }; - } - - public restoreViewState(s: editorCommon.ICodeEditorViewState): void { - if (!this.cursor || !this.hasView) { - return; - } - if (s && s.cursorState && s.viewState) { - let codeEditorState = s; - let cursorState = codeEditorState.cursorState; - if (Array.isArray(cursorState)) { - this.cursor.restoreState(cursorState); - } else { - // Backwards compatibility - this.cursor.restoreState([cursorState]); - } - - let contributionsState = s.contributionsState || {}; - let keys = Object.keys(this._contributions); - for (let i = 0, len = keys.length; i < len; i++) { - let id = keys[i]; - let contribution = this._contributions[id]; - if (typeof contribution.restoreViewState === 'function') { - contribution.restoreViewState(contributionsState[id]); - } - } - } - } - - public onVisible(): void { - } - - public onHide(): void { - } - - public abstract layout(dimension?: editorCommon.IDimension): void; - - public abstract focus(): void; - public abstract isFocused(): boolean; - public abstract hasWidgetFocus(): boolean; - - public getContribution(id: string): T { - return (this._contributions[id] || null); - } - - public getActions(): editorCommon.IEditorAction[] { - let result: editorCommon.IEditorAction[] = []; - - let keys = Object.keys(this._actions); - for (let i = 0, len = keys.length; i < len; i++) { - let id = keys[i]; - result.push(this._actions[id]); - } - - return result; - } - - public getSupportedActions(): editorCommon.IEditorAction[] { - let result = this.getActions(); - - result = result.filter(action => action.isSupported()); - - return result; - } - - public getAction(id: string): editorCommon.IEditorAction { - return this._actions[id] || null; - } - - public trigger(source: string, handlerId: string, payload: any): void { - payload = payload || {}; - - // Special case for typing - if (handlerId === editorCommon.Handler.Type) { - if (!this.cursor || typeof payload.text !== 'string' || payload.text.length === 0) { - // nothing to do - return; - } - if (source === 'keyboard') { - this._onWillType.fire(payload.text); - } - this.cursor.trigger(source, handlerId, payload); - if (source === 'keyboard') { - this._onDidType.fire(payload.text); - } - return; - } - - // Special case for pasting - if (handlerId === editorCommon.Handler.Paste) { - if (!this.cursor || typeof payload.text !== 'string' || payload.text.length === 0) { - // nothing to do - return; - } - const startPosition = this.cursor.getSelection().getStartPosition(); - this.cursor.trigger(source, handlerId, payload); - const endPosition = this.cursor.getSelection().getStartPosition(); - if (source === 'keyboard') { - this._onDidPaste.fire( - new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column) - ); - } - return; - } - - const action = this.getAction(handlerId); - if (action) { - TPromise.as(action.run()).then(null, onUnexpectedError); - return; - } - - if (!this.cursor) { - return; - } - - if (this._triggerEditorCommand(source, handlerId, payload)) { - return; - } - - this.cursor.trigger(source, handlerId, payload); - } - - protected abstract _triggerEditorCommand(source: string, handlerId: string, payload: any): boolean; - - public _getCursors(): ICursors { - return this.cursor; - } - - public _getCursorConfiguration(): CursorConfiguration { - return this.cursor.context.config; - } - - public pushUndoStop(): boolean { - if (!this.model) { - return false; - } - if (this._configuration.editor.readOnly) { - // read only editor => sorry! - return false; - } - this.model.pushStackElement(); - return true; - } - - public executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursorState?: Selection[]): boolean { - if (!this.cursor) { - // no view, no cursor - return false; - } - if (this._configuration.editor.readOnly) { - // read only editor => sorry! - return false; - } - - this.model.pushEditOperations(this.cursor.getSelections(), edits, () => { - return endCursorState ? endCursorState : null; - }); - - if (endCursorState) { - this.cursor.setSelections(source, endCursorState); - } - - return true; - } - - public executeCommand(source: string, command: editorCommon.ICommand): void { - if (!this.cursor) { - return; - } - this.cursor.trigger(source, editorCommon.Handler.ExecuteCommand, command); - } - - public executeCommands(source: string, commands: editorCommon.ICommand[]): void { - if (!this.cursor) { - return; - } - this.cursor.trigger(source, editorCommon.Handler.ExecuteCommands, commands); - } - - public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any { - if (!this.model) { - // console.warn('Cannot change decorations on editor that is not attached to a model'); - // callback will not be called - return null; - } - return this.model.changeDecorations(callback, this.id); - } - - public getLineDecorations(lineNumber: number): IModelDecoration[] { - if (!this.model) { - return null; - } - return this.model.getLineDecorations(lineNumber, this.id, this._configuration.editor.readOnly); - } - - public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] { - if (!this.model) { - return []; - } - - if (oldDecorations.length === 0 && newDecorations.length === 0) { - return oldDecorations; - } - - return this.model.deltaDecorations(oldDecorations, newDecorations, this.id); - } - - public setDecorations(decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void { - - let newDecorationsSubTypes: { [key: string]: boolean } = {}; - let oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; - this._decorationTypeSubtypes[decorationTypeKey] = newDecorationsSubTypes; - - let newModelDecorations: IModelDeltaDecoration[] = []; - - for (let decorationOption of decorationOptions) { - let typeKey = decorationTypeKey; - if (decorationOption.renderOptions) { - // identify custom reder options by a hash code over all keys and values - // For custom render options register a decoration type if necessary - let subType = hash(decorationOption.renderOptions).toString(16); - // The fact that `decorationTypeKey` appears in the typeKey has no influence - // it is just a mechanism to get predictable and unique keys (repeatable for the same options and unique across clients) - typeKey = decorationTypeKey + '-' + subType; - if (!oldDecorationsSubTypes[subType] && !newDecorationsSubTypes[subType]) { - // decoration type did not exist before, register new one - this._registerDecorationType(typeKey, decorationOption.renderOptions, decorationTypeKey); - } - newDecorationsSubTypes[subType] = true; - } - let opts = this._resolveDecorationOptions(typeKey, !!decorationOption.hoverMessage); - if (decorationOption.hoverMessage) { - opts.hoverMessage = decorationOption.hoverMessage; - } - newModelDecorations.push({ range: decorationOption.range, options: opts }); - } - - // remove decoration sub types that are no longer used, deregister decoration type if necessary - for (let subType in oldDecorationsSubTypes) { - if (!newDecorationsSubTypes[subType]) { - this._removeDecorationType(decorationTypeKey + '-' + subType); - } - } - - // update all decorations - let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || []; - this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); - } - - public setDecorationsFast(decorationTypeKey: string, ranges: IRange[]): void { - - // remove decoration sub types that are no longer used, deregister decoration type if necessary - let oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; - for (let subType in oldDecorationsSubTypes) { - this._removeDecorationType(decorationTypeKey + '-' + subType); - } - this._decorationTypeSubtypes[decorationTypeKey] = {}; - - const opts = ModelDecorationOptions.createDynamic(this._resolveDecorationOptions(decorationTypeKey, false)); - let newModelDecorations: IModelDeltaDecoration[] = new Array(ranges.length); - for (let i = 0, len = ranges.length; i < len; i++) { - newModelDecorations[i] = { range: ranges[i], options: opts }; - } - - // update all decorations - let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || []; - this._decorationTypeKeysToIds[decorationTypeKey] = this.deltaDecorations(oldDecorationsIds, newModelDecorations); - } - - public removeDecorations(decorationTypeKey: string): void { - // remove decorations for type and sub type - let oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey]; - if (oldDecorationsIds) { - this.deltaDecorations(oldDecorationsIds, []); - } - if (this._decorationTypeKeysToIds.hasOwnProperty(decorationTypeKey)) { - delete this._decorationTypeKeysToIds[decorationTypeKey]; - } - if (this._decorationTypeSubtypes.hasOwnProperty(decorationTypeKey)) { - delete this._decorationTypeSubtypes[decorationTypeKey]; - } - } - - public getLayoutInfo(): editorOptions.EditorLayoutInfo { - return this._configuration.editor.layoutInfo; - } - - protected _attachModel(model: ITextModel): void { - this.model = model ? model : null; - this.listenersToRemove = []; - this.viewModel = null; - this.cursor = null; - - if (this.model) { - this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language); - this._configuration.setIsDominatedByLongLines(this.model.isDominatedByLongLines()); - this._configuration.setMaxLineNumber(this.model.getLineCount()); - - this.model.onBeforeAttached(); - - this.viewModel = new ViewModel(this.id, this._configuration, this.model, (callback) => this._scheduleAtNextAnimationFrame(callback)); - - this.listenersToRemove.push(this.model.onDidChangeDecorations((e) => this._onDidChangeModelDecorations.fire(e))); - this.listenersToRemove.push(this.model.onDidChangeLanguage((e) => { - if (!this.model) { - return; - } - this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language); - this._onDidChangeModelLanguage.fire(e); - })); - this.listenersToRemove.push(this.model.onDidChangeLanguageConfiguration((e) => this._onDidChangeModelLanguageConfiguration.fire(e))); - this.listenersToRemove.push(this.model.onDidChangeContent((e) => this._onDidChangeModelContent.fire(e))); - this.listenersToRemove.push(this.model.onDidChangeOptions((e) => this._onDidChangeModelOptions.fire(e))); - // Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model - this.listenersToRemove.push(this.model.onWillDispose(() => this.setModel(null))); - - this.cursor = new Cursor( - this._configuration, - this.model, - this.viewModel - ); - - this._createView(); - - this.listenersToRemove.push(this.cursor.onDidReachMaxCursorCount(() => { - this._notificationService.warn(nls.localize('cursors.maximum', "The number of cursors has been limited to {0}.", Cursor.MAX_CURSOR_COUNT)); - })); - - this.listenersToRemove.push(this.cursor.onDidAttemptReadOnlyEdit(() => { - this._onDidAttemptReadOnlyEdit.fire(void 0); - })); - - this.listenersToRemove.push(this.cursor.onDidChange((e: CursorStateChangedEvent) => { - - let positions: Position[] = []; - for (let i = 0, len = e.selections.length; i < len; i++) { - positions[i] = e.selections[i].getPosition(); - } - - const e1: ICursorPositionChangedEvent = { - position: positions[0], - secondaryPositions: positions.slice(1), - reason: e.reason, - source: e.source - }; - this._onDidChangeCursorPosition.fire(e1); - - const e2: ICursorSelectionChangedEvent = { - selection: e.selections[0], - secondarySelections: e.selections.slice(1), - source: e.source, - reason: e.reason - }; - this._onDidChangeCursorSelection.fire(e2); - })); - - } else { - this.hasView = false; - } - } - - protected abstract _scheduleAtNextAnimationFrame(callback: () => void): IDisposable; - protected abstract _createView(): void; - - protected _postDetachModelCleanup(detachedModel: ITextModel): void { - if (detachedModel) { - detachedModel.removeAllDecorationsWithOwnerId(this.id); - } - } - - protected _detachModel(): ITextModel { - if (this.model) { - this.model.onBeforeDetached(); - } - - this.hasView = false; - - this.listenersToRemove = dispose(this.listenersToRemove); - - if (this.cursor) { - this.cursor.dispose(); - this.cursor = null; - } - - if (this.viewModel) { - this.viewModel.dispose(); - this.viewModel = null; - } - - let result = this.model; - this.model = null; - - this.domElement.removeAttribute('data-mode-id'); - - return result; - } - - protected abstract _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void; - protected abstract _removeDecorationType(key: string): void; - protected abstract _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions; - - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : {} - */ - public getTelemetryData(): { [key: string]: any; } { - return null; - } -} - -const enum BooleanEventValue { - NotSet, - False, - True -} - -export class BooleanEventEmitter extends Disposable { - private readonly _onDidChangeToTrue: Emitter = this._register(new Emitter()); - public readonly onDidChangeToTrue: Event = this._onDidChangeToTrue.event; - - private readonly _onDidChangeToFalse: Emitter = this._register(new Emitter()); - public readonly onDidChangeToFalse: Event = this._onDidChangeToFalse.event; - - private _value: BooleanEventValue; - - constructor() { - super(); - this._value = BooleanEventValue.NotSet; - } - - public setValue(_value: boolean) { - let value = (_value ? BooleanEventValue.True : BooleanEventValue.False); - if (this._value === value) { - return; - } - this._value = value; - if (this._value === BooleanEventValue.True) { - this._onDidChangeToTrue.fire(); - } else if (this._value === BooleanEventValue.False) { - this._onDidChangeToFalse.fire(); - } - } -} - -class EditorContextKeysManager extends Disposable { - - private _editor: CommonCodeEditor; - private _editorFocus: IContextKey; - private _textInputFocus: IContextKey; - private _editorTextFocus: IContextKey; - private _editorTabMovesFocus: IContextKey; - private _editorReadonly: IContextKey; - private _hasMultipleSelections: IContextKey; - private _hasNonEmptySelection: IContextKey; - - constructor( - editor: CommonCodeEditor, - contextKeyService: IContextKeyService - ) { - super(); - - this._editor = editor; - - contextKeyService.createKey('editorId', editor.getId()); - this._editorFocus = EditorContextKeys.focus.bindTo(contextKeyService); - this._textInputFocus = EditorContextKeys.textInputFocus.bindTo(contextKeyService); - this._editorTextFocus = EditorContextKeys.editorTextFocus.bindTo(contextKeyService); - this._editorTabMovesFocus = EditorContextKeys.tabMovesFocus.bindTo(contextKeyService); - this._editorReadonly = EditorContextKeys.readOnly.bindTo(contextKeyService); - this._hasMultipleSelections = EditorContextKeys.hasMultipleSelections.bindTo(contextKeyService); - this._hasNonEmptySelection = EditorContextKeys.hasNonEmptySelection.bindTo(contextKeyService); - - this._register(this._editor.onDidChangeConfiguration(() => this._updateFromConfig())); - this._register(this._editor.onDidChangeCursorSelection(() => this._updateFromSelection())); - this._register(this._editor.onDidFocusEditor(() => this._updateFromFocus())); - this._register(this._editor.onDidBlurEditor(() => this._updateFromFocus())); - this._register(this._editor.onDidFocusEditorText(() => this._updateFromFocus())); - this._register(this._editor.onDidBlurEditorText(() => this._updateFromFocus())); - - this._updateFromConfig(); - this._updateFromSelection(); - this._updateFromFocus(); - } - - private _updateFromConfig(): void { - let config = this._editor.getConfiguration(); - - this._editorTabMovesFocus.set(config.tabFocusMode); - this._editorReadonly.set(config.readOnly); - } - - private _updateFromSelection(): void { - let selections = this._editor.getSelections(); - if (!selections) { - this._hasMultipleSelections.reset(); - this._hasNonEmptySelection.reset(); - } else { - this._hasMultipleSelections.set(selections.length > 1); - this._hasNonEmptySelection.set(selections.some(s => !s.isEmpty())); - } - } - - private _updateFromFocus(): void { - this._editorFocus.set(this._editor.hasWidgetFocus() && !this._editor.isSimpleWidget); - this._editorTextFocus.set(this._editor.isFocused() && !this._editor.isSimpleWidget); - this._textInputFocus.set(this._editor.isFocused()); - } -} - -export class EditorModeContext extends Disposable { - - private _editor: CommonCodeEditor; - - private _langId: IContextKey; - private _hasCompletionItemProvider: IContextKey; - private _hasCodeActionsProvider: IContextKey; - private _hasCodeLensProvider: IContextKey; - private _hasDefinitionProvider: IContextKey; - private _hasImplementationProvider: IContextKey; - private _hasTypeDefinitionProvider: IContextKey; - private _hasHoverProvider: IContextKey; - private _hasDocumentHighlightProvider: IContextKey; - private _hasDocumentSymbolProvider: IContextKey; - private _hasReferenceProvider: IContextKey; - private _hasRenameProvider: IContextKey; - private _hasDocumentFormattingProvider: IContextKey; - private _hasDocumentSelectionFormattingProvider: IContextKey; - private _hasSignatureHelpProvider: IContextKey; - private _isInWalkThrough: IContextKey; - - constructor( - editor: CommonCodeEditor, - contextKeyService: IContextKeyService - ) { - super(); - this._editor = editor; - - this._langId = EditorContextKeys.languageId.bindTo(contextKeyService); - this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService); - this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService); - this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService); - this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(contextKeyService); - this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(contextKeyService); - this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService); - this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(contextKeyService); - this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService); - this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService); - this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService); - this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService); - this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService); - this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService); - this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService); - this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService); - - const update = () => this._update(); - - // update when model/mode changes - this._register(editor.onDidChangeModel(update)); - this._register(editor.onDidChangeModelLanguage(update)); - - // update when registries change - this._register(modes.SuggestRegistry.onDidChange(update)); - this._register(modes.CodeActionProviderRegistry.onDidChange(update)); - this._register(modes.CodeLensProviderRegistry.onDidChange(update)); - this._register(modes.DefinitionProviderRegistry.onDidChange(update)); - this._register(modes.ImplementationProviderRegistry.onDidChange(update)); - this._register(modes.TypeDefinitionProviderRegistry.onDidChange(update)); - this._register(modes.HoverProviderRegistry.onDidChange(update)); - this._register(modes.DocumentHighlightProviderRegistry.onDidChange(update)); - this._register(modes.DocumentSymbolProviderRegistry.onDidChange(update)); - this._register(modes.ReferenceProviderRegistry.onDidChange(update)); - this._register(modes.RenameProviderRegistry.onDidChange(update)); - this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update)); - this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update)); - this._register(modes.SignatureHelpProviderRegistry.onDidChange(update)); - - update(); - } - - dispose() { - super.dispose(); - } - - reset() { - this._langId.reset(); - this._hasCompletionItemProvider.reset(); - this._hasCodeActionsProvider.reset(); - this._hasCodeLensProvider.reset(); - this._hasDefinitionProvider.reset(); - this._hasImplementationProvider.reset(); - this._hasTypeDefinitionProvider.reset(); - this._hasHoverProvider.reset(); - this._hasDocumentHighlightProvider.reset(); - this._hasDocumentSymbolProvider.reset(); - this._hasReferenceProvider.reset(); - this._hasRenameProvider.reset(); - this._hasDocumentFormattingProvider.reset(); - this._hasDocumentSelectionFormattingProvider.reset(); - this._hasSignatureHelpProvider.reset(); - this._isInWalkThrough.reset(); - } - - private _update() { - const model = this._editor.getModel(); - if (!model) { - this.reset(); - return; - } - this._langId.set(model.getLanguageIdentifier().language); - this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model)); - this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model)); - this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model)); - this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model)); - this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model)); - this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model)); - this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model)); - this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model)); - this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model)); - this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model)); - this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model)); - this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model)); - this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model)); - this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model)); - this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet); - } -} diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 62af9556a22..a5d84b4f7be 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -90,6 +90,9 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions())); } + public observeReferenceElement(dimension?: editorCommon.IDimension): void { + } + public dispose(): void { super.dispose(); } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 8be479866df..bb9f0a7745f 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -150,12 +150,16 @@ export interface ILineChange extends IChange { /** * @internal */ -export interface IConfiguration { +export interface IConfiguration extends IDisposable { onDidChange(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable; readonly editor: editorOptions.InternalEditorOptions; setMaxLineNumber(maxLineNumber: number): void; + updateOptions(newOptions: editorOptions.IEditorOptions): void; + getRawOptions(): editorOptions.IEditorOptions; + observeReferenceElement(dimension?: IDimension): void; + setIsDominatedByLongLines(isDominatedByLongLines: boolean): void; } // --- view diff --git a/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts index e3ee7932fea..86dda0c7543 100644 --- a/src/vs/editor/test/browser/testCodeEditor.ts +++ b/src/vs/editor/test/browser/testCodeEditor.ts @@ -8,7 +8,6 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; -import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig'; import { Cursor } from 'vs/editor/common/controller/cursor'; import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; @@ -37,7 +36,7 @@ export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.IC } //#region testing overrides - protected _createConfiguration(options: editorOptions.IEditorOptions): CommonEditorConfiguration { + protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration { return new TestConfiguration(options); } protected _createView(): void { -- GitLab