mirror of
https://github.com/Microsoft/vscode
synced 2024-10-06 03:17:00 +00:00
Have the cursor be driven (with events) by the view model
This commit is contained in:
parent
cda6e7d7a5
commit
798a33f9c6
|
@ -4,6 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
@ -36,7 +37,6 @@ import { ScrollDecorationViewPart } from 'vs/editor/browser/viewParts/scrollDeco
|
|||
import { SelectionsOverlay } from 'vs/editor/browser/viewParts/selections/selections';
|
||||
import { ViewCursors } from 'vs/editor/browser/viewParts/viewCursors/viewCursors';
|
||||
import { ViewZones } from 'vs/editor/browser/viewParts/viewZones/viewZones';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
|
@ -68,7 +68,7 @@ export class View extends ViewEventHandler {
|
|||
|
||||
private _scrollbar: EditorScrollbar;
|
||||
private readonly _context: ViewContext;
|
||||
private readonly _cursor: Cursor;
|
||||
private _selections: Selection[];
|
||||
|
||||
// The view lines
|
||||
private viewLines: ViewLines;
|
||||
|
@ -98,11 +98,10 @@ export class View extends ViewEventHandler {
|
|||
configuration: IConfiguration,
|
||||
themeService: IThemeService,
|
||||
model: IViewModel,
|
||||
cursor: Cursor,
|
||||
outgoingEvents: ViewOutgoingEvents
|
||||
) {
|
||||
super();
|
||||
this._cursor = cursor;
|
||||
this._selections = [new Selection(1, 1, 1, 1)];
|
||||
this._renderAnimationFrame = null;
|
||||
this.outgoingEvents = outgoingEvents;
|
||||
|
||||
|
@ -229,10 +228,6 @@ export class View extends ViewEventHandler {
|
|||
this._register(model.addViewEventListener((events: viewEvents.ViewEvent[]) => {
|
||||
this.eventDispatcher.emitMany(events);
|
||||
}));
|
||||
|
||||
this._register(this._cursor.addViewEventListener((events: viewEvents.ViewEvent[]) => {
|
||||
this.eventDispatcher.emitMany(events);
|
||||
}));
|
||||
}
|
||||
|
||||
private _flushAccumulatedAndRenderNow(): void {
|
||||
|
@ -315,6 +310,10 @@ export class View extends ViewEventHandler {
|
|||
this.outgoingEvents.emitContentSizeChange(e);
|
||||
return false;
|
||||
}
|
||||
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
|
||||
this._selections = e.selections;
|
||||
return false;
|
||||
}
|
||||
public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {
|
||||
this.domNode.setClassName(this.getEditorClassName());
|
||||
this._context.model.setHasFocus(e.isFocused);
|
||||
|
@ -404,7 +403,7 @@ export class View extends ViewEventHandler {
|
|||
this._context.model.setViewport(partialViewportData.startLineNumber, partialViewportData.endLineNumber, partialViewportData.centeredLineNumber);
|
||||
|
||||
const viewportData = new ViewportData(
|
||||
this._cursor.getViewSelections(),
|
||||
this._selections,
|
||||
partialViewportData,
|
||||
this._context.viewLayout.getWhitespaceViewportData(),
|
||||
this._context.model
|
||||
|
|
|
@ -80,15 +80,13 @@ export interface ICodeEditorWidgetOptions {
|
|||
class ModelData {
|
||||
public readonly model: ITextModel;
|
||||
public readonly viewModel: ViewModel;
|
||||
public readonly cursor: Cursor;
|
||||
public readonly view: View;
|
||||
public readonly hasRealView: boolean;
|
||||
public readonly listenersToRemove: IDisposable[];
|
||||
|
||||
constructor(model: ITextModel, viewModel: ViewModel, cursor: Cursor, view: View, hasRealView: boolean, listenersToRemove: IDisposable[]) {
|
||||
constructor(model: ITextModel, viewModel: ViewModel, view: View, hasRealView: boolean, listenersToRemove: IDisposable[]) {
|
||||
this.model = model;
|
||||
this.viewModel = viewModel;
|
||||
this.cursor = cursor;
|
||||
this.view = view;
|
||||
this.hasRealView = hasRealView;
|
||||
this.listenersToRemove = listenersToRemove;
|
||||
|
@ -100,7 +98,6 @@ class ModelData {
|
|||
if (this.hasRealView) {
|
||||
this.view.dispose();
|
||||
}
|
||||
this.cursor.dispose();
|
||||
this.viewModel.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +527,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (!this._modelData) {
|
||||
return null;
|
||||
}
|
||||
return this._modelData.cursor.getPosition();
|
||||
return this._modelData.viewModel.cursor.getPosition();
|
||||
}
|
||||
|
||||
public setPosition(position: IPosition): void {
|
||||
|
@ -540,7 +537,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (!Position.isIPosition(position)) {
|
||||
throw new Error('Invalid arguments');
|
||||
}
|
||||
this._modelData.cursor.setSelections('api', [{
|
||||
this._modelData.viewModel.cursor.setSelections('api', [{
|
||||
selectionStartLineNumber: position.lineNumber,
|
||||
selectionStartColumn: position.column,
|
||||
positionLineNumber: position.lineNumber,
|
||||
|
@ -558,7 +555,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
const validatedModelRange = this._modelData.model.validateRange(modelRange);
|
||||
const viewRange = this._modelData.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange);
|
||||
|
||||
this._modelData.cursor.emitCursorRevealRange('api', viewRange, null, verticalType, revealHorizontal, scrollType);
|
||||
this._modelData.viewModel.cursor.emitCursorRevealRange('api', viewRange, null, verticalType, revealHorizontal, scrollType);
|
||||
}
|
||||
|
||||
public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||
|
@ -643,14 +640,14 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (!this._modelData) {
|
||||
return null;
|
||||
}
|
||||
return this._modelData.cursor.getSelection();
|
||||
return this._modelData.viewModel.cursor.getSelection();
|
||||
}
|
||||
|
||||
public getSelections(): Selection[] | null {
|
||||
if (!this._modelData) {
|
||||
return null;
|
||||
}
|
||||
return this._modelData.cursor.getSelections();
|
||||
return this._modelData.viewModel.cursor.getSelections();
|
||||
}
|
||||
|
||||
public setSelection(range: IRange): void;
|
||||
|
@ -684,7 +681,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
return;
|
||||
}
|
||||
const selection = new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);
|
||||
this._modelData.cursor.setSelections('api', [selection]);
|
||||
this._modelData.viewModel.cursor.setSelections('api', [selection]);
|
||||
}
|
||||
|
||||
public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
|
||||
|
@ -815,7 +812,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
throw new Error('Invalid arguments');
|
||||
}
|
||||
}
|
||||
this._modelData.cursor.setSelections(source, ranges);
|
||||
this._modelData.viewModel.cursor.setSelections(source, ranges);
|
||||
}
|
||||
|
||||
public getContentWidth(): number {
|
||||
|
@ -901,7 +898,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
}
|
||||
}
|
||||
|
||||
const cursorState = this._modelData.cursor.saveState();
|
||||
const cursorState = this._modelData.viewModel.cursor.saveState();
|
||||
const viewState = this._modelData.viewModel.saveState();
|
||||
return {
|
||||
cursorState: cursorState,
|
||||
|
@ -918,10 +915,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (codeEditorState && codeEditorState.cursorState && codeEditorState.viewState) {
|
||||
const cursorState = <any>codeEditorState.cursorState;
|
||||
if (Array.isArray(cursorState)) {
|
||||
this._modelData.cursor.restoreState(<editorCommon.ICursorState[]>cursorState);
|
||||
this._modelData.viewModel.cursor.restoreState(<editorCommon.ICursorState[]>cursorState);
|
||||
} else {
|
||||
// Backwards compatibility
|
||||
this._modelData.cursor.restoreState([<editorCommon.ICursorState>cursorState]);
|
||||
this._modelData.viewModel.cursor.restoreState([<editorCommon.ICursorState>cursorState]);
|
||||
}
|
||||
|
||||
const contributionsState = codeEditorState.contributionsState || {};
|
||||
|
@ -988,7 +985,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (source === 'keyboard') {
|
||||
this._onWillType.fire(payload.text);
|
||||
}
|
||||
this._modelData.cursor.trigger(source, handlerId, payload);
|
||||
this._modelData.viewModel.cursor.trigger(source, handlerId, payload);
|
||||
if (source === 'keyboard') {
|
||||
this._onDidType.fire(payload.text);
|
||||
}
|
||||
|
@ -1001,9 +998,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
// nothing to do
|
||||
return;
|
||||
}
|
||||
const startPosition = this._modelData.cursor.getSelection().getStartPosition();
|
||||
this._modelData.cursor.trigger(source, handlerId, payload);
|
||||
const endPosition = this._modelData.cursor.getSelection().getStartPosition();
|
||||
const startPosition = this._modelData.viewModel.cursor.getSelection().getStartPosition();
|
||||
this._modelData.viewModel.cursor.trigger(source, handlerId, payload);
|
||||
const endPosition = this._modelData.viewModel.cursor.getSelection().getStartPosition();
|
||||
if (source === 'keyboard') {
|
||||
this._onDidPaste.fire(
|
||||
{
|
||||
|
@ -1029,7 +1026,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
return;
|
||||
}
|
||||
|
||||
this._modelData.cursor.trigger(source, handlerId, payload);
|
||||
this._modelData.viewModel.cursor.trigger(source, handlerId, payload);
|
||||
|
||||
if (handlerId === editorCommon.Handler.CompositionStart) {
|
||||
this._onDidCompositionStart.fire();
|
||||
|
@ -1057,7 +1054,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (!this._modelData) {
|
||||
return null;
|
||||
}
|
||||
return this._modelData.cursor;
|
||||
return this._modelData.viewModel.cursor;
|
||||
}
|
||||
|
||||
public _getViewModel(): IViewModel | null {
|
||||
|
@ -1097,7 +1094,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
cursorStateComputer = endCursorState;
|
||||
}
|
||||
|
||||
this._modelData.cursor.executeEdits(source, edits, cursorStateComputer);
|
||||
this._modelData.viewModel.cursor.executeEdits(source, edits, cursorStateComputer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1105,14 +1102,14 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
if (!this._modelData) {
|
||||
return;
|
||||
}
|
||||
this._modelData.cursor.trigger(source, editorCommon.Handler.ExecuteCommand, command);
|
||||
this._modelData.viewModel.cursor.trigger(source, editorCommon.Handler.ExecuteCommand, command);
|
||||
}
|
||||
|
||||
public executeCommands(source: string | null | undefined, commands: editorCommon.ICommand[]): void {
|
||||
if (!this._modelData) {
|
||||
return;
|
||||
}
|
||||
this._modelData.cursor.trigger(source, editorCommon.Handler.ExecuteCommands, commands);
|
||||
this._modelData.viewModel.cursor.trigger(source, editorCommon.Handler.ExecuteCommands, commands);
|
||||
}
|
||||
|
||||
public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
|
||||
|
@ -1445,17 +1442,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
// Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model
|
||||
listenersToRemove.push(model.onWillDispose(() => this.setModel(null)));
|
||||
|
||||
const cursor = new Cursor(this._configuration, model, viewModel, viewModel.coordinatesConverter);
|
||||
|
||||
listenersToRemove.push(cursor.onDidReachMaxCursorCount(() => {
|
||||
listenersToRemove.push(viewModel.cursor.onDidReachMaxCursorCount(() => {
|
||||
this._notificationService.warn(nls.localize('cursors.maximum', "The number of cursors has been limited to {0}.", Cursor.MAX_CURSOR_COUNT));
|
||||
}));
|
||||
|
||||
listenersToRemove.push(cursor.onDidAttemptReadOnlyEdit(() => {
|
||||
listenersToRemove.push(viewModel.cursor.onDidAttemptReadOnlyEdit(() => {
|
||||
this._onDidAttemptReadOnlyEdit.fire(undefined);
|
||||
}));
|
||||
|
||||
listenersToRemove.push(cursor.onDidChange((e: CursorStateChangedEvent) => {
|
||||
listenersToRemove.push(viewModel.cursor.onDidChange((e: CursorStateChangedEvent) => {
|
||||
const positions: Position[] = [];
|
||||
for (let i = 0, len = e.selections.length; i < len; i++) {
|
||||
positions[i] = e.selections[i].getPosition();
|
||||
|
@ -1481,7 +1476,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
this._onDidChangeCursorSelection.fire(e2);
|
||||
}));
|
||||
|
||||
const [view, hasRealView] = this._createView(viewModel, cursor);
|
||||
const [view, hasRealView] = this._createView(viewModel);
|
||||
if (hasRealView) {
|
||||
this._domElement.appendChild(view.domNode.domNode);
|
||||
|
||||
|
@ -1501,15 +1496,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
view.domNode.domNode.setAttribute('data-uri', model.uri.toString());
|
||||
}
|
||||
|
||||
this._modelData = new ModelData(model, viewModel, cursor, view, hasRealView, listenersToRemove);
|
||||
this._modelData = new ModelData(model, viewModel, view, hasRealView, listenersToRemove);
|
||||
}
|
||||
|
||||
protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] {
|
||||
protected _createView(viewModel: ViewModel): [View, boolean] {
|
||||
let commandDelegate: ICommandDelegate;
|
||||
if (this.isSimpleWidget) {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(cursor, args);
|
||||
editorCommand.runCoreEditorCommand(viewModel.cursor, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
this.trigger('keyboard', editorCommon.Handler.Paste, { text, pasteOnNewLine, multicursorText, mode });
|
||||
|
@ -1533,7 +1528,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
} else {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(cursor, args);
|
||||
editorCommand.runCoreEditorCommand(viewModel.cursor, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.Paste, {
|
||||
|
@ -1568,7 +1563,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
|
||||
const onDidChangeTextFocus = (textFocus: boolean) => {
|
||||
if (this._modelData) {
|
||||
this._modelData.cursor.setHasFocus(textFocus);
|
||||
this._modelData.viewModel.cursor.setHasFocus(textFocus);
|
||||
}
|
||||
this._editorTextFocus.setValue(textFocus);
|
||||
};
|
||||
|
@ -1594,7 +1589,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
|||
this._configuration,
|
||||
this._themeService,
|
||||
viewModel,
|
||||
cursor,
|
||||
viewOutgoingEvents
|
||||
);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
|||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { CursorCollection } from 'vs/editor/common/controller/cursorCollection';
|
||||
import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget, IReducedViewModel } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations';
|
||||
|
@ -16,21 +16,12 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
|||
import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';
|
||||
import { RawContentChangedType, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { RawContentChangedType, ModelRawContentChangedEvent, IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditorOption, ConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean {
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
if (events[i].type === viewEvents.ViewEventType.ViewLineMappingChanged) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export class CursorStateChangedEvent {
|
||||
/**
|
||||
* The new selections.
|
||||
|
@ -182,7 +173,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
private readonly _configuration: editorCommon.IConfiguration;
|
||||
private readonly _model: ITextModel;
|
||||
private _knownModelVersionId: number;
|
||||
private readonly _viewModel: IReducedViewModel;
|
||||
private readonly _viewModel: ICursorSimpleModel;
|
||||
private readonly _coordinatesConverter: ICoordinatesConverter;
|
||||
public context: CursorContext;
|
||||
private _cursors: CursorCollection;
|
||||
|
@ -195,7 +186,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
private _autoClosedActions: AutoClosedAction[];
|
||||
private _prevEditOperationType: EditOperationType;
|
||||
|
||||
constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IReducedViewModel, coordinatesConverter: ICoordinatesConverter) {
|
||||
constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter) {
|
||||
super();
|
||||
this._configuration = configuration;
|
||||
this._model = model;
|
||||
|
@ -212,53 +203,6 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
this._columnSelectData = null;
|
||||
this._autoClosedActions = [];
|
||||
this._prevEditOperationType = EditOperationType.Other;
|
||||
|
||||
this._register(this._model.onDidChangeRawContent((e) => {
|
||||
this._knownModelVersionId = e.versionId;
|
||||
if (this._isHandling) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._onModelContentChanged(e);
|
||||
}));
|
||||
|
||||
this._register(viewModel.addViewEventListener((events: viewEvents.ViewEvent[]) => {
|
||||
if (!containsLineMappingChanged(events)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._knownModelVersionId !== this._model.getVersionId()) {
|
||||
// There are model change events that I didn't yet receive.
|
||||
//
|
||||
// This can happen when editing the model, and the view model receives the change events first,
|
||||
// and the view model emits line mapping changed events, all before the cursor gets a chance to
|
||||
// recover from markers.
|
||||
//
|
||||
// The model change listener above will be called soon and we'll ensure a valid cursor state there.
|
||||
return;
|
||||
}
|
||||
// Ensure valid state
|
||||
this.setStates('viewModel', CursorChangeReason.NotSet, this.getAll());
|
||||
}));
|
||||
|
||||
const updateCursorContext = () => {
|
||||
this.context = new CursorContext(this._configuration, this._model, this._viewModel, this._coordinatesConverter);
|
||||
this._cursors.updateContext(this.context);
|
||||
};
|
||||
this._register(this._model.onDidChangeLanguage((e) => {
|
||||
updateCursorContext();
|
||||
}));
|
||||
this._register(this._model.onDidChangeLanguageConfiguration(() => {
|
||||
updateCursorContext();
|
||||
}));
|
||||
this._register(this._model.onDidChangeOptions(() => {
|
||||
updateCursorContext();
|
||||
}));
|
||||
this._register(this._configuration.onDidChange((e) => {
|
||||
if (CursorConfiguration.shouldRecreate(e)) {
|
||||
updateCursorContext();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
@ -267,6 +211,44 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
private _updateCursorContext(): void {
|
||||
this.context = new CursorContext(this._configuration, this._model, this._viewModel, this._coordinatesConverter);
|
||||
this._cursors.updateContext(this.context);
|
||||
}
|
||||
|
||||
public onLineMappingChanged(): void {
|
||||
if (this._knownModelVersionId !== this._model.getVersionId()) {
|
||||
// There are model change events that I didn't yet receive.
|
||||
//
|
||||
// This can happen when editing the model, and the view model receives the change events first,
|
||||
// and the view model emits line mapping changed events, all before the cursor gets a chance to
|
||||
// recover from markers.
|
||||
//
|
||||
// The model change listener above will be called soon and we'll ensure a valid cursor state there.
|
||||
return;
|
||||
}
|
||||
// Ensure valid state
|
||||
this.setStates('viewModel', CursorChangeReason.NotSet, this.getAll());
|
||||
}
|
||||
|
||||
public onDidChangeModelLanguage(e: IModelLanguageChangedEvent): void {
|
||||
this._updateCursorContext();
|
||||
}
|
||||
|
||||
public onDidChangeModelLanguageConfiguration(): void {
|
||||
this._updateCursorContext();
|
||||
}
|
||||
|
||||
public onDidChangeModelOptions(): void {
|
||||
this._updateCursorContext();
|
||||
}
|
||||
|
||||
public onDidChangeConfiguration(e: ConfigurationChangedEvent): void {
|
||||
if (CursorConfiguration.shouldRecreate(e)) {
|
||||
this._updateCursorContext();
|
||||
}
|
||||
}
|
||||
|
||||
public setHasFocus(hasFocus: boolean): void {
|
||||
this._hasFocus = hasFocus;
|
||||
}
|
||||
|
@ -393,7 +375,12 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate);
|
||||
}
|
||||
|
||||
private _onModelContentChanged(e: ModelRawContentChangedEvent): void {
|
||||
public onModelContentChanged(e: ModelRawContentChangedEvent): void {
|
||||
|
||||
this._knownModelVersionId = e.versionId;
|
||||
if (this._isHandling) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);
|
||||
this._prevEditOperationType = EditOperationType.Other;
|
||||
|
@ -441,10 +428,6 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||
return this._cursors.getSelections();
|
||||
}
|
||||
|
||||
public getViewSelections(): Selection[] {
|
||||
return this._cursors.getViewSelections();
|
||||
}
|
||||
|
||||
public getPosition(): Position {
|
||||
return this._cursors.getPrimaryCursor().modelState.position;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TextModel } from 'vs/editor/common/model/textModel';
|
|||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { IAutoClosingPair, StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { VerticalRevealType, IViewEventEmitter } from 'vs/editor/common/view/viewEvents';
|
||||
import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
|
||||
import { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
|
||||
|
@ -351,18 +351,15 @@ export class SingleCursorState {
|
|||
}
|
||||
}
|
||||
|
||||
export interface IReducedViewModel extends ICursorSimpleModel, IViewEventEmitter {
|
||||
}
|
||||
|
||||
export class CursorContext {
|
||||
_cursorContextBrand: void;
|
||||
|
||||
public readonly model: ITextModel;
|
||||
public readonly viewModel: IReducedViewModel;
|
||||
public readonly viewModel: ICursorSimpleModel;
|
||||
public readonly coordinatesConverter: ICoordinatesConverter;
|
||||
public readonly config: CursorConfiguration;
|
||||
|
||||
constructor(configuration: IConfiguration, model: ITextModel, viewModel: IReducedViewModel, coordinatesConverter: ICoordinatesConverter) {
|
||||
constructor(configuration: IConfiguration, model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter) {
|
||||
this.model = model;
|
||||
this.viewModel = viewModel;
|
||||
this.coordinatesConverter = coordinatesConverter;
|
||||
|
|
|
@ -14,7 +14,7 @@ import { IViewEventEmitter } from 'vs/editor/common/view/viewEvents';
|
|||
import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
||||
import { IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
import { IReducedViewModel } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon';
|
||||
|
||||
export interface IViewWhitespaceViewportData {
|
||||
readonly id: string;
|
||||
|
@ -94,7 +94,7 @@ export interface ICoordinatesConverter {
|
|||
modelPositionIsVisible(modelPosition: Position): boolean;
|
||||
}
|
||||
|
||||
export interface IViewModel extends IViewEventEmitter, IReducedViewModel {
|
||||
export interface IViewModel extends IViewEventEmitter, ICursorSimpleModel {
|
||||
|
||||
readonly coordinatesConverter: ICoordinatesConverter;
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecora
|
|||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
import { IReducedViewModel } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
|
||||
const USE_IDENTITY_LINES_COLLECTION = true;
|
||||
|
||||
export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel, IReducedViewModel {
|
||||
export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel {
|
||||
|
||||
private readonly editorId: number;
|
||||
private readonly configuration: IConfiguration;
|
||||
|
@ -42,6 +42,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
private readonly lines: IViewModelLinesCollection;
|
||||
public readonly coordinatesConverter: ICoordinatesConverter;
|
||||
public readonly viewLayout: ViewLayout;
|
||||
public readonly cursor: Cursor;
|
||||
private readonly decorations: ViewModelDecorations;
|
||||
|
||||
constructor(
|
||||
|
@ -89,6 +90,18 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
|
||||
this.coordinatesConverter = this.lines.createCoordinatesConverter();
|
||||
|
||||
this.cursor = this._register(new Cursor(this.configuration, model, this, this.coordinatesConverter));
|
||||
this._register(this.cursor.addViewEventListener((events) => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmitViewEvents();
|
||||
for (const event of events) {
|
||||
eventsCollector.emit(event);
|
||||
}
|
||||
} finally {
|
||||
this._endEmitViewEvents();
|
||||
}
|
||||
}));
|
||||
|
||||
this.viewLayout = this._register(new ViewLayout(this.configuration, this.getLineCount(), scheduleAtNextAnimationFrame));
|
||||
|
||||
this._register(this.viewLayout.onDidScroll((e) => {
|
||||
|
@ -167,6 +180,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.cursor.onLineMappingChanged();
|
||||
this.decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
|
||||
|
@ -192,6 +206,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
const viewPositionTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
|
||||
this.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this.viewportStartLineDelta }, ScrollType.Immediate);
|
||||
}
|
||||
|
||||
this.cursor.onDidChangeConfiguration(e);
|
||||
}
|
||||
|
||||
private _registerModelEvents(): void {
|
||||
|
@ -288,6 +304,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
if (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.cursor.onLineMappingChanged();
|
||||
this.decorations.onLineMappingChanged();
|
||||
}
|
||||
} finally {
|
||||
|
@ -308,6 +325,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
this.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this.viewportStartLineDelta }, ScrollType.Immediate);
|
||||
}
|
||||
}
|
||||
|
||||
this.cursor.onModelContentChanged(e);
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeTokens((e) => {
|
||||
|
@ -330,11 +349,17 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
|
||||
this._register(this.model.onDidChangeLanguageConfiguration((e) => {
|
||||
this._emitSingleViewEvent(new viewEvents.ViewLanguageConfigurationEvent());
|
||||
this.cursor.onDidChangeModelLanguageConfiguration();
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeLanguage((e) => {
|
||||
this.cursor.onDidChangeModelLanguage(e);
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeOptions((e) => {
|
||||
// A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here
|
||||
if (this.lines.setTabSize(this.model.getOptions().tabSize)) {
|
||||
this.cursor.onLineMappingChanged();
|
||||
this.decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
try {
|
||||
|
@ -347,6 +372,8 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
}
|
||||
this._updateConfigurationViewLineCount.schedule();
|
||||
}
|
||||
|
||||
this.cursor.onDidChangeModelOptions();
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeDecorations((e) => {
|
||||
|
@ -363,6 +390,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
|||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.cursor.onLineMappingChanged();
|
||||
this.decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
this.viewLayout.onHeightMaybeChanged();
|
||||
|
|
|
@ -33,7 +33,7 @@ export class TestCodeEditor extends CodeEditorWidget implements ICodeEditor {
|
|||
protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): IConfiguration {
|
||||
return new TestConfiguration(options);
|
||||
}
|
||||
protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] {
|
||||
protected _createView(viewModel: ViewModel): [View, boolean] {
|
||||
// Never create a view
|
||||
return [null! as View, false];
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export class TestCodeEditor extends CodeEditorWidget implements ICodeEditor {
|
|||
|
||||
//#region Testing utils
|
||||
public getCursor(): Cursor | undefined {
|
||||
return this._modelData ? this._modelData.cursor : undefined;
|
||||
return this._modelData ? this._modelData.viewModel.cursor : undefined;
|
||||
}
|
||||
public registerAndInstantiateContribution<T extends IEditorContribution, Services extends BrandedService[]>(id: string, ctor: new (editor: ICodeEditor, ...services: Services) => T): T {
|
||||
const r: T = this._instantiationService.createInstance(ctor as IEditorContributionCtor, this);
|
||||
|
|
|
@ -77,7 +77,7 @@ suite('ViewModelDecorations', () => {
|
|||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3))
|
||||
).map((dec) => {
|
||||
return dec.options.className;
|
||||
});
|
||||
}).filter(Boolean);
|
||||
|
||||
assert.deepEqual(actualDecorations, [
|
||||
'dec1',
|
||||
|
@ -292,7 +292,7 @@ suite('ViewModelDecorations', () => {
|
|||
|
||||
let decorations = viewModel.getDecorationsInViewport(
|
||||
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3))
|
||||
);
|
||||
).filter(x => Boolean(x.options.beforeContentClassName));
|
||||
assert.deepEqual(decorations, []);
|
||||
|
||||
let inlineDecorations1 = viewModel.getViewLineRenderingData(
|
||||
|
|
|
@ -70,7 +70,7 @@ suite('ViewModel', () => {
|
|||
model.undo();
|
||||
viewLineCount.push(viewModel.getLineCount());
|
||||
|
||||
assert.deepEqual(viewLineCount, [4, 1, 1, 1]);
|
||||
assert.deepEqual(viewLineCount, [4, 1, 1, 1, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue