mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2
This commit is contained in:
@@ -283,6 +283,9 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
private _onDidChange = this._register(new Emitter<ConfigurationChangedEvent>());
|
||||
public readonly onDidChange: Event<ConfigurationChangedEvent> = this._onDidChange.event;
|
||||
|
||||
private _onDidChangeFast = this._register(new Emitter<ConfigurationChangedEvent>());
|
||||
public readonly onDidChangeFast: Event<ConfigurationChangedEvent> = this._onDidChangeFast.event;
|
||||
|
||||
public readonly isSimpleWidget: boolean;
|
||||
private _computeOptionsMemory: ComputeOptionsMemory;
|
||||
public options!: ComputedEditorOptions;
|
||||
@@ -334,6 +337,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
|
||||
}
|
||||
|
||||
this.options = newOptions;
|
||||
this._onDidChangeFast.fire(changeEvent);
|
||||
this._onDidChange.fire(changeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,11 @@ export interface IEditorOptions {
|
||||
* Defaults to true.
|
||||
*/
|
||||
renderFinalNewline?: boolean;
|
||||
/**
|
||||
* Remove unusual line terminators like LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS), NEXT LINE (NEL).
|
||||
* Defaults to true.
|
||||
*/
|
||||
removeUnusualLineTerminators?: boolean;
|
||||
/**
|
||||
* Should the corresponding line be selected when clicking on the line number?
|
||||
* Defaults to true.
|
||||
@@ -2878,8 +2883,8 @@ class EditorScrollbar extends BaseEditorOption<EditorOption.scrollbar, InternalE
|
||||
useShadows: true,
|
||||
verticalHasArrows: false,
|
||||
horizontalHasArrows: false,
|
||||
horizontalScrollbarSize: 10,
|
||||
horizontalSliderSize: 10,
|
||||
horizontalScrollbarSize: 12,
|
||||
horizontalSliderSize: 12,
|
||||
verticalScrollbarSize: 14,
|
||||
verticalSliderSize: 14,
|
||||
handleMouseWheel: true,
|
||||
@@ -3555,6 +3560,7 @@ export const enum EditorOption {
|
||||
quickSuggestions,
|
||||
quickSuggestionsDelay,
|
||||
readOnly,
|
||||
removeUnusualLineTerminators,
|
||||
renameOnType,
|
||||
renderControlCharacters,
|
||||
renderIndentGuides,
|
||||
@@ -3973,6 +3979,10 @@ export const EditorOptions = {
|
||||
readOnly: register(new EditorBooleanOption(
|
||||
EditorOption.readOnly, 'readOnly', false,
|
||||
)),
|
||||
removeUnusualLineTerminators: register(new EditorBooleanOption(
|
||||
EditorOption.removeUnusualLineTerminators, 'removeUnusualLineTerminators', true,
|
||||
{ description: nls.localize('removeUnusualLineTerminators', "Remove unusual line terminators that might cause problems.") }
|
||||
)),
|
||||
renameOnType: register(new EditorBooleanOption(
|
||||
EditorOption.renameOnType, 'renameOnType', false,
|
||||
{ description: nls.localize('renameOnType', "Controls whether the editor auto renames on type.") }
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, PartialCursorState, 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';
|
||||
@@ -17,56 +16,10 @@ import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core
|
||||
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 * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
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.
|
||||
* The primary selection is always at index 0.
|
||||
*/
|
||||
readonly selections: Selection[];
|
||||
/**
|
||||
* The new model version id that `selections` apply to.
|
||||
*/
|
||||
readonly modelVersionId: number;
|
||||
/**
|
||||
* The old selections.
|
||||
*/
|
||||
readonly oldSelections: Selection[] | null;
|
||||
/**
|
||||
* The model version id the that `oldSelections` apply to.
|
||||
*/
|
||||
readonly oldModelVersionId: number;
|
||||
/**
|
||||
* Source of the call that caused the event.
|
||||
*/
|
||||
readonly source: string;
|
||||
/**
|
||||
* Reason.
|
||||
*/
|
||||
readonly reason: CursorChangeReason;
|
||||
|
||||
constructor(selections: Selection[], modelVersionId: number, oldSelections: Selection[] | null, oldModelVersionId: number, source: string, reason: CursorChangeReason) {
|
||||
this.selections = selections;
|
||||
this.modelVersionId = modelVersionId;
|
||||
this.oldSelections = oldSelections;
|
||||
this.oldModelVersionId = oldModelVersionId;
|
||||
this.source = source;
|
||||
this.reason = reason;
|
||||
}
|
||||
}
|
||||
import { VerticalRevealType, ViewCursorStateChangedEvent, ViewRevealRangeRequestEvent } from 'vs/editor/common/view/viewEvents';
|
||||
import { dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { CursorStateChangedEvent, ViewModelEventsCollector } from 'vs/editor/common/viewModel/viewModelEventDispatcher';
|
||||
|
||||
/**
|
||||
* A snapshot of the cursor and the model state
|
||||
@@ -78,7 +31,7 @@ export class CursorModelState {
|
||||
|
||||
constructor(model: ITextModel, cursor: Cursor) {
|
||||
this.modelVersionId = model.getVersionId();
|
||||
this.cursorState = cursor.getAll();
|
||||
this.cursorState = cursor.getCursorStates();
|
||||
}
|
||||
|
||||
public equals(other: CursorModelState | null): boolean {
|
||||
@@ -166,23 +119,14 @@ class AutoClosedAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
export class Cursor extends Disposable {
|
||||
|
||||
public static readonly MAX_CURSOR_COUNT = 10000;
|
||||
|
||||
private readonly _onDidReachMaxCursorCount: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidReachMaxCursorCount: Event<void> = this._onDidReachMaxCursorCount.event;
|
||||
|
||||
private readonly _onDidAttemptReadOnlyEdit: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidAttemptReadOnlyEdit: Event<void> = this._onDidAttemptReadOnlyEdit.event;
|
||||
|
||||
private readonly _onDidChange: Emitter<CursorStateChangedEvent> = this._register(new Emitter<CursorStateChangedEvent>());
|
||||
public readonly onDidChange: Event<CursorStateChangedEvent> = this._onDidChange.event;
|
||||
|
||||
private readonly _configuration: editorCommon.IConfiguration;
|
||||
private readonly _model: ITextModel;
|
||||
private _knownModelVersionId: number;
|
||||
private readonly _viewModel: IViewModel;
|
||||
private readonly _viewModel: ICursorSimpleModel;
|
||||
private readonly _coordinatesConverter: ICoordinatesConverter;
|
||||
public context: CursorContext;
|
||||
private _cursors: CursorCollection;
|
||||
|
||||
@@ -194,13 +138,13 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
private _autoClosedActions: AutoClosedAction[];
|
||||
private _prevEditOperationType: EditOperationType;
|
||||
|
||||
constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) {
|
||||
constructor(model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {
|
||||
super();
|
||||
this._configuration = configuration;
|
||||
this._model = model;
|
||||
this._knownModelVersionId = this._model.getVersionId();
|
||||
this._viewModel = viewModel;
|
||||
this.context = new CursorContext(this._configuration, this._model, this._viewModel);
|
||||
this._coordinatesConverter = coordinatesConverter;
|
||||
this.context = new CursorContext(this._model, this._coordinatesConverter, cursorConfig);
|
||||
this._cursors = new CursorCollection(this.context);
|
||||
|
||||
this._hasFocus = false;
|
||||
@@ -210,53 +154,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.addEventListener((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._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 {
|
||||
@@ -265,6 +162,26 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public updateConfiguration(cursorConfig: CursorConfiguration): void {
|
||||
this.context = new CursorContext(this._model, this._coordinatesConverter, cursorConfig);
|
||||
this._cursors.updateContext(this.context);
|
||||
}
|
||||
|
||||
public onLineMappingChanged(eventsCollector: ViewModelEventsCollector): 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(eventsCollector, 'viewModel', CursorChangeReason.NotSet, this.getCursorStates());
|
||||
}
|
||||
|
||||
public setHasFocus(hasFocus: boolean): void {
|
||||
this._hasFocus = hasFocus;
|
||||
}
|
||||
@@ -285,7 +202,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
|
||||
// ------ some getters/setters
|
||||
|
||||
public getPrimaryCursor(): CursorState {
|
||||
public getPrimaryCursorState(): CursorState {
|
||||
return this._cursors.getPrimaryCursor();
|
||||
}
|
||||
|
||||
@@ -293,14 +210,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
return this._cursors.getLastAddedCursorIndex();
|
||||
}
|
||||
|
||||
public getAll(): CursorState[] {
|
||||
public getCursorStates(): CursorState[] {
|
||||
return this._cursors.getAll();
|
||||
}
|
||||
|
||||
public setStates(source: string, reason: CursorChangeReason, states: PartialCursorState[] | null): boolean {
|
||||
public setStates(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): boolean {
|
||||
let reachedMaxCursorCount = false;
|
||||
if (states !== null && states.length > Cursor.MAX_CURSOR_COUNT) {
|
||||
states = states.slice(0, Cursor.MAX_CURSOR_COUNT);
|
||||
this._onDidReachMaxCursorCount.fire(undefined);
|
||||
reachedMaxCursorCount = true;
|
||||
}
|
||||
|
||||
const oldState = new CursorModelState(this._model, this);
|
||||
@@ -311,25 +229,38 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
|
||||
this._validateAutoClosedActions();
|
||||
|
||||
return this._emitStateChangedIfNecessary(source, reason, oldState);
|
||||
return this._emitStateChangedIfNecessary(eventsCollector, source, reason, oldState, reachedMaxCursorCount);
|
||||
}
|
||||
|
||||
public setColumnSelectData(columnSelectData: IColumnSelectData): void {
|
||||
public setCursorColumnSelectData(columnSelectData: IColumnSelectData): void {
|
||||
this._columnSelectData = columnSelectData;
|
||||
}
|
||||
|
||||
public reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: editorCommon.ScrollType): void {
|
||||
this._revealRange(source, target, viewEvents.VerticalRevealType.Simple, horizontal, scrollType);
|
||||
public revealPrimary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
|
||||
const viewPositions = this._cursors.getViewPositions();
|
||||
if (viewPositions.length > 1) {
|
||||
this._emitCursorRevealRange(eventsCollector, source, null, this._cursors.getViewSelections(), VerticalRevealType.Simple, revealHorizontal, scrollType);
|
||||
return;
|
||||
} else {
|
||||
const viewPosition = viewPositions[0];
|
||||
const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
|
||||
this._emitCursorRevealRange(eventsCollector, source, viewRange, null, VerticalRevealType.Simple, revealHorizontal, scrollType);
|
||||
}
|
||||
}
|
||||
|
||||
public revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: editorCommon.ScrollType) {
|
||||
this.emitCursorRevealRange(source, viewRange, null, verticalType, revealHorizontal, scrollType);
|
||||
private _revealPrimaryCursor(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
|
||||
const viewPositions = this._cursors.getViewPositions();
|
||||
if (viewPositions.length > 1) {
|
||||
this._emitCursorRevealRange(eventsCollector, source, null, this._cursors.getViewSelections(), verticalType, revealHorizontal, scrollType);
|
||||
} else {
|
||||
const viewPosition = viewPositions[0];
|
||||
const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
|
||||
this._emitCursorRevealRange(eventsCollector, source, viewRange, null, verticalType, revealHorizontal, scrollType);
|
||||
}
|
||||
}
|
||||
|
||||
public scrollTo(desiredScrollTop: number): void {
|
||||
this._viewModel.viewLayout.setScrollPositionSmooth({
|
||||
scrollTop: desiredScrollTop
|
||||
});
|
||||
private _emitCursorRevealRange(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, viewRange: Range | null, viewSelections: Selection[] | null, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) {
|
||||
eventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, viewRange, viewSelections, verticalType, revealHorizontal, scrollType));
|
||||
}
|
||||
|
||||
public saveState(): editorCommon.ICursorState[] {
|
||||
@@ -356,7 +287,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
return result;
|
||||
}
|
||||
|
||||
public restoreState(states: editorCommon.ICursorState[]): void {
|
||||
public restoreState(eventsCollector: ViewModelEventsCollector, states: editorCommon.ICursorState[]): void {
|
||||
|
||||
let desiredSelections: ISelection[] = [];
|
||||
|
||||
@@ -393,11 +324,16 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
});
|
||||
}
|
||||
|
||||
this.setStates('restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections));
|
||||
this.reveal('restoreState', true, RevealTarget.Primary, editorCommon.ScrollType.Immediate);
|
||||
this.setStates(eventsCollector, 'restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections));
|
||||
this.revealPrimary(eventsCollector, 'restoreState', true, editorCommon.ScrollType.Immediate);
|
||||
}
|
||||
|
||||
private _onModelContentChanged(e: ModelRawContentChangedEvent): void {
|
||||
public onModelContentChanged(eventsCollector: ViewModelEventsCollector, e: ModelRawContentChangedEvent): void {
|
||||
|
||||
this._knownModelVersionId = e.versionId;
|
||||
if (this._isHandling) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);
|
||||
this._prevEditOperationType = EditOperationType.Other;
|
||||
@@ -407,16 +343,16 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
this._cursors.dispose();
|
||||
this._cursors = new CursorCollection(this.context);
|
||||
this._validateAutoClosedActions();
|
||||
this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null);
|
||||
this._emitStateChangedIfNecessary(eventsCollector, 'model', CursorChangeReason.ContentFlush, null, false);
|
||||
} else {
|
||||
if (this._hasFocus && e.resultingSelection && e.resultingSelection.length > 0) {
|
||||
const cursorState = CursorState.fromModelSelections(e.resultingSelection);
|
||||
if (this.setStates('modelChange', e.isUndoing ? CursorChangeReason.Undo : e.isRedoing ? CursorChangeReason.Redo : CursorChangeReason.RecoverFromMarkers, cursorState)) {
|
||||
this._revealRange('modelChange', RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);
|
||||
if (this.setStates(eventsCollector, 'modelChange', e.isUndoing ? CursorChangeReason.Undo : e.isRedoing ? CursorChangeReason.Redo : CursorChangeReason.RecoverFromMarkers, cursorState)) {
|
||||
this._revealPrimaryCursor(eventsCollector, 'modelChange', VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);
|
||||
}
|
||||
} else {
|
||||
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
|
||||
this.setStates('modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));
|
||||
this.setStates(eventsCollector, 'modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,7 +361,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
return this._cursors.getPrimaryCursor().modelState.selection;
|
||||
}
|
||||
|
||||
public getColumnSelectData(): IColumnSelectData {
|
||||
public getTopMostViewPosition(): Position {
|
||||
return this._cursors.getTopMostViewPosition();
|
||||
}
|
||||
|
||||
public getBottomMostViewPosition(): Position {
|
||||
return this._cursors.getBottomMostViewPosition();
|
||||
}
|
||||
|
||||
public getCursorColumnSelectData(): IColumnSelectData {
|
||||
if (this._columnSelectData) {
|
||||
return this._columnSelectData;
|
||||
}
|
||||
@@ -435,9 +379,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
return {
|
||||
isReal: false,
|
||||
fromViewLineNumber: viewSelectionStart.lineNumber,
|
||||
fromViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, viewSelectionStart),
|
||||
fromViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.cursorConfig, this._viewModel, viewSelectionStart),
|
||||
toViewLineNumber: viewPosition.lineNumber,
|
||||
toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, viewPosition),
|
||||
toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.cursorConfig, this._viewModel, viewPosition),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -445,16 +389,12 @@ 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;
|
||||
}
|
||||
|
||||
public setSelections(source: string, selections: readonly ISelection[]): void {
|
||||
this.setStates(source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections));
|
||||
public setSelections(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, selections: readonly ISelection[]): void {
|
||||
this.setStates(eventsCollector, source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections));
|
||||
}
|
||||
|
||||
public getPrevEditOperationType(): EditOperationType {
|
||||
@@ -545,7 +485,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
// ----- emitting events
|
||||
|
||||
private _emitStateChangedIfNecessary(source: string, reason: CursorChangeReason, oldState: CursorModelState | null): boolean {
|
||||
private _emitStateChangedIfNecessary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, oldState: CursorModelState | null, reachedMaxCursorCount: boolean): boolean {
|
||||
const newState = new CursorModelState(this._model, this);
|
||||
if (newState.equals(oldState)) {
|
||||
return false;
|
||||
@@ -555,12 +495,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
const viewSelections = this._cursors.getViewSelections();
|
||||
|
||||
// Let the view get the event first.
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewCursorStateChangedEvent(viewSelections, selections));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
eventsCollector.emitViewEvent(new ViewCursorStateChangedEvent(viewSelections, selections));
|
||||
|
||||
// Only after the view has been notified, let the rest of the world know...
|
||||
if (!oldState
|
||||
@@ -569,49 +504,12 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
) {
|
||||
const oldSelections = oldState ? oldState.cursorState.map(s => s.modelState.selection) : null;
|
||||
const oldModelVersionId = oldState ? oldState.modelVersionId : 0;
|
||||
this._onDidChange.fire(new CursorStateChangedEvent(selections, newState.modelVersionId, oldSelections, oldModelVersionId, source || 'keyboard', reason));
|
||||
eventsCollector.emitOutgoingEvent(new CursorStateChangedEvent(oldSelections, selections, oldModelVersionId, newState.modelVersionId, source || 'keyboard', reason, reachedMaxCursorCount));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private _revealRange(source: string, revealTarget: RevealTarget, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
|
||||
const viewPositions = this._cursors.getViewPositions();
|
||||
|
||||
let viewPosition = viewPositions[0];
|
||||
|
||||
if (revealTarget === RevealTarget.TopMost) {
|
||||
for (let i = 1; i < viewPositions.length; i++) {
|
||||
if (viewPositions[i].isBefore(viewPosition)) {
|
||||
viewPosition = viewPositions[i];
|
||||
}
|
||||
}
|
||||
} else if (revealTarget === RevealTarget.BottomMost) {
|
||||
for (let i = 1; i < viewPositions.length; i++) {
|
||||
if (viewPosition.isBeforeOrEqual(viewPositions[i])) {
|
||||
viewPosition = viewPositions[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (viewPositions.length > 1) {
|
||||
this.emitCursorRevealRange(source, null, this._cursors.getViewSelections(), verticalType, revealHorizontal, scrollType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
|
||||
this.emitCursorRevealRange(source, viewRange, null, verticalType, revealHorizontal, scrollType);
|
||||
}
|
||||
|
||||
public emitCursorRevealRange(source: string, viewRange: Range | null, viewSelections: Selection[] | null, verticalType: viewEvents.VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType) {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, viewSelections, verticalType, revealHorizontal, scrollType));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
// ----- handlers beyond this point
|
||||
|
||||
@@ -633,7 +531,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
}
|
||||
const closeChar = m[1];
|
||||
|
||||
const autoClosingPairsCandidates = this.context.config.autoClosingPairsClose2.get(closeChar);
|
||||
const autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairsClose2.get(closeChar);
|
||||
if (!autoClosingPairsCandidates || autoClosingPairsCandidates.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
@@ -651,7 +549,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
return indices;
|
||||
}
|
||||
|
||||
public executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {
|
||||
public executeEdits(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {
|
||||
let autoClosingIndices: [number, number][] | null = null;
|
||||
if (source === 'snippet') {
|
||||
autoClosingIndices = this._findAutoClosingPairs(edits);
|
||||
@@ -686,146 +584,117 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
});
|
||||
if (selections) {
|
||||
this._isHandling = false;
|
||||
this.setSelections(source, selections);
|
||||
this.setSelections(eventsCollector, source, selections);
|
||||
}
|
||||
if (autoClosedCharactersRanges.length > 0) {
|
||||
this._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);
|
||||
}
|
||||
}
|
||||
|
||||
public trigger(source: string, handlerId: string, payload: any): void {
|
||||
const H = editorCommon.Handler;
|
||||
|
||||
if (handlerId === H.CompositionStart) {
|
||||
this._isDoingComposition = true;
|
||||
this._selectionsWhenCompositionStarted = this.getSelections().slice(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlerId === H.CompositionEnd) {
|
||||
this._isDoingComposition = false;
|
||||
}
|
||||
|
||||
if (this._configuration.options.get(EditorOption.readOnly)) {
|
||||
// All the remaining handlers will try to edit the model,
|
||||
// but we cannot edit when read only...
|
||||
this._onDidAttemptReadOnlyEdit.fire(undefined);
|
||||
private _executeEdit(callback: () => void, eventsCollector: ViewModelEventsCollector, source: string | null | undefined, cursorChangeReason: CursorChangeReason = CursorChangeReason.NotSet): void {
|
||||
if (this.context.cursorConfig.readOnly) {
|
||||
// we cannot edit when read only...
|
||||
return;
|
||||
}
|
||||
|
||||
const oldState = new CursorModelState(this._model, this);
|
||||
let cursorChangeReason = CursorChangeReason.NotSet;
|
||||
|
||||
this._cursors.stopTrackingSelections();
|
||||
|
||||
// ensure valid state on all cursors
|
||||
this._cursors.ensureValidState();
|
||||
|
||||
this._isHandling = true;
|
||||
|
||||
try {
|
||||
switch (handlerId) {
|
||||
case H.Type:
|
||||
this._type(source, <string>payload.text);
|
||||
break;
|
||||
|
||||
case H.ReplacePreviousChar:
|
||||
this._replacePreviousChar(<string>payload.text, <number>payload.replaceCharCnt);
|
||||
break;
|
||||
|
||||
case H.Paste:
|
||||
cursorChangeReason = CursorChangeReason.Paste;
|
||||
this._paste(<string>payload.text, <boolean>payload.pasteOnNewLine, <string[]>payload.multicursorText || []);
|
||||
break;
|
||||
|
||||
case H.Cut:
|
||||
this._cut();
|
||||
break;
|
||||
|
||||
case H.ExecuteCommand:
|
||||
this._externalExecuteCommand(<editorCommon.ICommand>payload);
|
||||
break;
|
||||
|
||||
case H.ExecuteCommands:
|
||||
this._externalExecuteCommands(<editorCommon.ICommand[]>payload);
|
||||
break;
|
||||
|
||||
case H.CompositionEnd:
|
||||
this._interpretCompositionEnd(source);
|
||||
break;
|
||||
}
|
||||
this._cursors.ensureValidState();
|
||||
callback();
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
}
|
||||
|
||||
this._isHandling = false;
|
||||
|
||||
this._cursors.startTrackingSelections();
|
||||
|
||||
this._validateAutoClosedActions();
|
||||
|
||||
if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) {
|
||||
this._revealRange(source, RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);
|
||||
if (this._emitStateChangedIfNecessary(eventsCollector, source, cursorChangeReason, oldState, false)) {
|
||||
this._revealPrimaryCursor(eventsCollector, source, VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);
|
||||
}
|
||||
}
|
||||
|
||||
private _interpretCompositionEnd(source: string) {
|
||||
if (!this._isDoingComposition && source === 'keyboard') {
|
||||
// composition finishes, let's check if we need to auto complete if necessary.
|
||||
const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);
|
||||
this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this._selectionsWhenCompositionStarted, this.getSelections(), autoClosedCharacters));
|
||||
this._selectionsWhenCompositionStarted = null;
|
||||
}
|
||||
public setIsDoingComposition(isDoingComposition: boolean): void {
|
||||
this._isDoingComposition = isDoingComposition;
|
||||
}
|
||||
|
||||
private _type(source: string, text: string): void {
|
||||
if (source === 'keyboard') {
|
||||
// If this event is coming straight from the keyboard, look for electric characters and enter
|
||||
public startComposition(eventsCollector: ViewModelEventsCollector): void {
|
||||
this._selectionsWhenCompositionStarted = this.getSelections().slice(0);
|
||||
}
|
||||
|
||||
const len = text.length;
|
||||
let offset = 0;
|
||||
while (offset < len) {
|
||||
const charLength = strings.nextCharLength(text, offset);
|
||||
const chr = text.substr(offset, charLength);
|
||||
|
||||
// Here we must interpret each typed character individually
|
||||
public endComposition(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
if (source === 'keyboard') {
|
||||
// composition finishes, let's check if we need to auto complete if necessary.
|
||||
const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);
|
||||
this._executeEditOperation(TypeOperations.typeWithInterceptors(this._isDoingComposition, this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr));
|
||||
|
||||
offset += charLength;
|
||||
this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this._selectionsWhenCompositionStarted, this.getSelections(), autoClosedCharacters));
|
||||
this._selectionsWhenCompositionStarted = null;
|
||||
}
|
||||
|
||||
} else {
|
||||
this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text));
|
||||
}
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
private _replacePreviousChar(text: string, replaceCharCnt: number): void {
|
||||
this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt));
|
||||
public type(eventsCollector: ViewModelEventsCollector, text: string, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
if (source === 'keyboard') {
|
||||
// If this event is coming straight from the keyboard, look for electric characters and enter
|
||||
|
||||
const len = text.length;
|
||||
let offset = 0;
|
||||
while (offset < len) {
|
||||
const charLength = strings.nextCharLength(text, offset);
|
||||
const chr = text.substr(offset, charLength);
|
||||
|
||||
// Here we must interpret each typed character individually
|
||||
const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);
|
||||
this._executeEditOperation(TypeOperations.typeWithInterceptors(this._isDoingComposition, this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), autoClosedCharacters, chr));
|
||||
|
||||
offset += charLength;
|
||||
}
|
||||
|
||||
} else {
|
||||
this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text));
|
||||
}
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
private _paste(text: string, pasteOnNewLine: boolean, multicursorText: string[]): void {
|
||||
this._executeEditOperation(TypeOperations.paste(this.context.config, this.context.model, this.getSelections(), text, pasteOnNewLine, multicursorText));
|
||||
public replacePreviousChar(eventsCollector: ViewModelEventsCollector, text: string, replaceCharCnt: number, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replaceCharCnt));
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
private _cut(): void {
|
||||
this._executeEditOperation(DeleteOperations.cut(this.context.config, this.context.model, this.getSelections()));
|
||||
public paste(eventsCollector: ViewModelEventsCollector, text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
this._executeEditOperation(TypeOperations.paste(this.context.cursorConfig, this._model, this.getSelections(), text, pasteOnNewLine, multicursorText || []));
|
||||
}, eventsCollector, source, CursorChangeReason.Paste);
|
||||
}
|
||||
|
||||
private _externalExecuteCommand(command: editorCommon.ICommand): void {
|
||||
this._cursors.killSecondaryCursors();
|
||||
|
||||
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], {
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: false
|
||||
}));
|
||||
public cut(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
this._executeEditOperation(DeleteOperations.cut(this.context.cursorConfig, this._model, this.getSelections()));
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
private _externalExecuteCommands(commands: editorCommon.ICommand[]): void {
|
||||
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, {
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: false
|
||||
}));
|
||||
public executeCommand(eventsCollector: ViewModelEventsCollector, command: editorCommon.ICommand, source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
this._cursors.killSecondaryCursors();
|
||||
|
||||
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], {
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: false
|
||||
}));
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
|
||||
public executeCommands(eventsCollector: ViewModelEventsCollector, commands: editorCommon.ICommand[], source?: string | null | undefined): void {
|
||||
this._executeEdit(() => {
|
||||
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, {
|
||||
shouldPushStackElementBefore: false,
|
||||
shouldPushStackElementAfter: false
|
||||
}));
|
||||
}, eventsCollector, source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,28 @@ export class CursorCollection {
|
||||
return result;
|
||||
}
|
||||
|
||||
public getTopMostViewPosition(): Position {
|
||||
let result = this.primaryCursor.viewState.position;
|
||||
for (let i = 0, len = this.secondaryCursors.length; i < len; i++) {
|
||||
const viewPosition = this.secondaryCursors[i].viewState.position;
|
||||
if (viewPosition.isBefore(result)) {
|
||||
result = viewPosition;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public getBottomMostViewPosition(): Position {
|
||||
let result = this.primaryCursor.viewState.position;
|
||||
for (let i = 0, len = this.secondaryCursors.length; i < len; i++) {
|
||||
const viewPosition = this.secondaryCursors[i].viewState.position;
|
||||
if (result.isBeforeOrEqual(viewPosition)) {
|
||||
result = viewPosition;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public getSelections(): Selection[] {
|
||||
let result: Selection[] = [];
|
||||
result[0] = this.primaryCursor.modelState.selection;
|
||||
@@ -204,7 +226,7 @@ export class CursorCollection {
|
||||
const currentSelection = current.selection;
|
||||
const nextSelection = next.selection;
|
||||
|
||||
if (!this.context.config.multiCursorMergeOverlapping) {
|
||||
if (!this.context.cursorConfig.multiCursorMergeOverlapping) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,18 +7,16 @@ import { CharCode } from 'vs/base/common/charCode';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { EditorAutoClosingStrategy, EditorAutoSurroundStrategy, ConfigurationChangedEvent, EditorAutoClosingOvertypeStrategy, EditorOption, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { ICommand, IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { ICommand, IConfiguration } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
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 } from 'vs/editor/common/view/viewEvents';
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
|
||||
export interface IColumnSelectData {
|
||||
@@ -46,25 +44,6 @@ export const enum EditOperationType {
|
||||
DeletingRight = 3
|
||||
}
|
||||
|
||||
export interface ICursors {
|
||||
readonly context: CursorContext;
|
||||
getPrimaryCursor(): CursorState;
|
||||
getLastAddedCursorIndex(): number;
|
||||
getAll(): CursorState[];
|
||||
|
||||
getColumnSelectData(): IColumnSelectData;
|
||||
setColumnSelectData(columnSelectData: IColumnSelectData): void;
|
||||
|
||||
setStates(source: string, reason: CursorChangeReason, states: PartialCursorState[] | null): void;
|
||||
reveal(source: string, horizontal: boolean, target: RevealTarget, scrollType: ScrollType): void;
|
||||
revealRange(source: string, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void;
|
||||
|
||||
scrollTo(desiredScrollTop: number): void;
|
||||
|
||||
getPrevEditOperationType(): EditOperationType;
|
||||
setPrevEditOperationType(type: EditOperationType): void;
|
||||
}
|
||||
|
||||
export interface CharacterMap {
|
||||
[char: string]: string;
|
||||
}
|
||||
@@ -357,62 +336,13 @@ export class CursorContext {
|
||||
_cursorContextBrand: void;
|
||||
|
||||
public readonly model: ITextModel;
|
||||
public readonly viewModel: IViewModel;
|
||||
public readonly config: CursorConfiguration;
|
||||
public readonly coordinatesConverter: ICoordinatesConverter;
|
||||
public readonly cursorConfig: CursorConfiguration;
|
||||
|
||||
constructor(configuration: IConfiguration, model: ITextModel, viewModel: IViewModel) {
|
||||
constructor(model: ITextModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {
|
||||
this.model = model;
|
||||
this.viewModel = viewModel;
|
||||
this.config = new CursorConfiguration(
|
||||
this.model.getLanguageIdentifier(),
|
||||
this.model.getOptions(),
|
||||
configuration
|
||||
);
|
||||
}
|
||||
|
||||
public validateViewPosition(viewPosition: Position, modelPosition: Position): Position {
|
||||
return this.viewModel.coordinatesConverter.validateViewPosition(viewPosition, modelPosition);
|
||||
}
|
||||
|
||||
public validateViewRange(viewRange: Range, expectedModelRange: Range): Range {
|
||||
return this.viewModel.coordinatesConverter.validateViewRange(viewRange, expectedModelRange);
|
||||
}
|
||||
|
||||
public convertViewRangeToModelRange(viewRange: Range): Range {
|
||||
return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
|
||||
}
|
||||
|
||||
public convertViewPositionToModelPosition(lineNumber: number, column: number): Position {
|
||||
return this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber, column));
|
||||
}
|
||||
|
||||
public convertModelPositionToViewPosition(modelPosition: Position): Position {
|
||||
return this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
|
||||
}
|
||||
|
||||
public convertModelRangeToViewRange(modelRange: Range): Range {
|
||||
return this.viewModel.coordinatesConverter.convertModelRangeToViewRange(modelRange);
|
||||
}
|
||||
|
||||
public getCurrentScrollTop(): number {
|
||||
return this.viewModel.viewLayout.getCurrentScrollTop();
|
||||
}
|
||||
|
||||
public getCompletelyVisibleViewRange(): Range {
|
||||
return this.viewModel.getCompletelyVisibleViewRange();
|
||||
}
|
||||
|
||||
public getCompletelyVisibleModelRange(): Range {
|
||||
const viewRange = this.viewModel.getCompletelyVisibleViewRange();
|
||||
return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
|
||||
}
|
||||
|
||||
public getCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range {
|
||||
return this.viewModel.getCompletelyVisibleViewRangeAtScrollTop(scrollTop);
|
||||
}
|
||||
|
||||
public getVerticalOffsetForViewLine(viewLineNumber: number): number {
|
||||
return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewLineNumber);
|
||||
this.coordinatesConverter = coordinatesConverter;
|
||||
this.cursorConfig = cursorConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,131 +4,132 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { CursorContext, CursorState, ICursorSimpleModel, PartialCursorState, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { CursorState, ICursorSimpleModel, PartialCursorState, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations';
|
||||
import { WordOperations } from 'vs/editor/common/controller/cursorWordOperations';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
export class CursorMoveCommands {
|
||||
|
||||
public static addCursorDown(context: CursorContext, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {
|
||||
public static addCursorDown(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [], resultLen = 0;
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);
|
||||
if (useLogicalLine) {
|
||||
result[resultLen++] = CursorState.fromModelState(MoveOperations.translateDown(context.config, context.model, cursor.modelState));
|
||||
result[resultLen++] = CursorState.fromModelState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel.model, cursor.modelState));
|
||||
} else {
|
||||
result[resultLen++] = CursorState.fromViewState(MoveOperations.translateDown(context.config, context.viewModel, cursor.viewState));
|
||||
result[resultLen++] = CursorState.fromViewState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel, cursor.viewState));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static addCursorUp(context: CursorContext, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {
|
||||
public static addCursorUp(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [], resultLen = 0;
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);
|
||||
if (useLogicalLine) {
|
||||
result[resultLen++] = CursorState.fromModelState(MoveOperations.translateUp(context.config, context.model, cursor.modelState));
|
||||
result[resultLen++] = CursorState.fromModelState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel.model, cursor.modelState));
|
||||
} else {
|
||||
result[resultLen++] = CursorState.fromViewState(MoveOperations.translateUp(context.config, context.viewModel, cursor.viewState));
|
||||
result[resultLen++] = CursorState.fromViewState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel, cursor.viewState));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static moveToBeginningOfLine(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
public static moveToBeginningOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = this._moveToLineStart(context, cursor, inSelectionMode);
|
||||
result[i] = this._moveToLineStart(viewModel, cursor, inSelectionMode);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToLineStart(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineStart(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
const currentViewStateColumn = cursor.viewState.position.column;
|
||||
const currentModelStateColumn = cursor.modelState.position.column;
|
||||
const isFirstLineOfWrappedLine = currentViewStateColumn === currentModelStateColumn;
|
||||
|
||||
const currentViewStatelineNumber = cursor.viewState.position.lineNumber;
|
||||
const firstNonBlankColumn = context.viewModel.getLineFirstNonWhitespaceColumn(currentViewStatelineNumber);
|
||||
const firstNonBlankColumn = viewModel.getLineFirstNonWhitespaceColumn(currentViewStatelineNumber);
|
||||
const isBeginningOfViewLine = currentViewStateColumn === firstNonBlankColumn;
|
||||
|
||||
if (!isFirstLineOfWrappedLine && !isBeginningOfViewLine) {
|
||||
return this._moveToLineStartByView(context, cursor, inSelectionMode);
|
||||
return this._moveToLineStartByView(viewModel, cursor, inSelectionMode);
|
||||
} else {
|
||||
return this._moveToLineStartByModel(context, cursor, inSelectionMode);
|
||||
return this._moveToLineStartByModel(viewModel, cursor, inSelectionMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static _moveToLineStartByView(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineStartByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
return CursorState.fromViewState(
|
||||
MoveOperations.moveToBeginningOfLine(context.config, context.viewModel, cursor.viewState, inSelectionMode)
|
||||
MoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)
|
||||
);
|
||||
}
|
||||
|
||||
private static _moveToLineStartByModel(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineStartByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
return CursorState.fromModelState(
|
||||
MoveOperations.moveToBeginningOfLine(context.config, context.model, cursor.modelState, inSelectionMode)
|
||||
MoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)
|
||||
);
|
||||
}
|
||||
|
||||
public static moveToEndOfLine(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
public static moveToEndOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = this._moveToLineEnd(context, cursor, inSelectionMode);
|
||||
result[i] = this._moveToLineEnd(viewModel, cursor, inSelectionMode);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToLineEnd(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineEnd(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
const viewStatePosition = cursor.viewState.position;
|
||||
const viewModelMaxColumn = context.viewModel.getLineMaxColumn(viewStatePosition.lineNumber);
|
||||
const viewModelMaxColumn = viewModel.getLineMaxColumn(viewStatePosition.lineNumber);
|
||||
const isEndOfViewLine = viewStatePosition.column === viewModelMaxColumn;
|
||||
|
||||
const modelStatePosition = cursor.modelState.position;
|
||||
const modelMaxColumn = context.model.getLineMaxColumn(modelStatePosition.lineNumber);
|
||||
const modelMaxColumn = viewModel.model.getLineMaxColumn(modelStatePosition.lineNumber);
|
||||
const isEndLineOfWrappedLine = viewModelMaxColumn - viewStatePosition.column === modelMaxColumn - modelStatePosition.column;
|
||||
|
||||
if (isEndOfViewLine || isEndLineOfWrappedLine) {
|
||||
return this._moveToLineEndByModel(context, cursor, inSelectionMode);
|
||||
return this._moveToLineEndByModel(viewModel, cursor, inSelectionMode);
|
||||
} else {
|
||||
return this._moveToLineEndByView(context, cursor, inSelectionMode);
|
||||
return this._moveToLineEndByView(viewModel, cursor, inSelectionMode);
|
||||
}
|
||||
}
|
||||
|
||||
private static _moveToLineEndByView(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineEndByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
return CursorState.fromViewState(
|
||||
MoveOperations.moveToEndOfLine(context.config, context.viewModel, cursor.viewState, inSelectionMode)
|
||||
MoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)
|
||||
);
|
||||
}
|
||||
|
||||
private static _moveToLineEndByModel(context: CursorContext, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
private static _moveToLineEndByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {
|
||||
return CursorState.fromModelState(
|
||||
MoveOperations.moveToEndOfLine(context.config, context.model, cursor.modelState, inSelectionMode)
|
||||
MoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)
|
||||
);
|
||||
}
|
||||
|
||||
public static expandLineSelection(context: CursorContext, cursors: CursorState[]): PartialCursorState[] {
|
||||
public static expandLineSelection(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
|
||||
const startLineNumber = cursor.modelState.selection.startLineNumber;
|
||||
const lineCount = context.model.getLineCount();
|
||||
const lineCount = viewModel.model.getLineCount();
|
||||
|
||||
let endLineNumber = cursor.modelState.selection.endLineNumber;
|
||||
let endColumn: number;
|
||||
if (endLineNumber === lineCount) {
|
||||
endColumn = context.model.getLineMaxColumn(lineCount);
|
||||
endColumn = viewModel.model.getLineMaxColumn(lineCount);
|
||||
} else {
|
||||
endLineNumber++;
|
||||
endColumn = 1;
|
||||
@@ -142,27 +143,27 @@ export class CursorMoveCommands {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static moveToBeginningOfBuffer(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
public static moveToBeginningOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveToBeginningOfBuffer(context.config, context.model, cursor.modelState, inSelectionMode));
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveToBeginningOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static moveToEndOfBuffer(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
public static moveToEndOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveToEndOfBuffer(context.config, context.model, cursor.modelState, inSelectionMode));
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveToEndOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static selectAll(context: CursorContext, cursor: CursorState): PartialCursorState {
|
||||
const lineCount = context.model.getLineCount();
|
||||
const maxColumn = context.model.getLineMaxColumn(lineCount);
|
||||
public static selectAll(viewModel: IViewModel, cursor: CursorState): PartialCursorState {
|
||||
const lineCount = viewModel.model.getLineCount();
|
||||
const maxColumn = viewModel.model.getLineMaxColumn(lineCount);
|
||||
|
||||
return CursorState.fromModelState(new SingleCursorState(
|
||||
new Range(1, 1, 1, 1), 0,
|
||||
@@ -170,23 +171,23 @@ export class CursorMoveCommands {
|
||||
));
|
||||
}
|
||||
|
||||
public static line(context: CursorContext, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {
|
||||
const position = context.model.validatePosition(_position);
|
||||
public static line(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {
|
||||
const position = viewModel.model.validatePosition(_position);
|
||||
const viewPosition = (
|
||||
_viewPosition
|
||||
? context.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)
|
||||
: context.convertModelPositionToViewPosition(position)
|
||||
? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)
|
||||
: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)
|
||||
);
|
||||
|
||||
if (!inSelectionMode || !cursor.modelState.hasSelection()) {
|
||||
// Entering line selection for the first time
|
||||
const lineCount = context.model.getLineCount();
|
||||
const lineCount = viewModel.model.getLineCount();
|
||||
|
||||
let selectToLineNumber = position.lineNumber + 1;
|
||||
let selectToColumn = 1;
|
||||
if (selectToLineNumber > lineCount) {
|
||||
selectToLineNumber = lineCount;
|
||||
selectToColumn = context.model.getLineMaxColumn(selectToLineNumber);
|
||||
selectToColumn = viewModel.model.getLineMaxColumn(selectToLineNumber);
|
||||
}
|
||||
|
||||
return CursorState.fromModelState(new SingleCursorState(
|
||||
@@ -206,13 +207,13 @@ export class CursorMoveCommands {
|
||||
|
||||
} else if (position.lineNumber > enteringLineNumber) {
|
||||
|
||||
const lineCount = context.viewModel.getLineCount();
|
||||
const lineCount = viewModel.getLineCount();
|
||||
|
||||
let selectToViewLineNumber = viewPosition.lineNumber + 1;
|
||||
let selectToViewColumn = 1;
|
||||
if (selectToViewLineNumber > lineCount) {
|
||||
selectToViewLineNumber = lineCount;
|
||||
selectToViewColumn = context.viewModel.getLineMaxColumn(selectToViewLineNumber);
|
||||
selectToViewColumn = viewModel.getLineMaxColumn(selectToViewLineNumber);
|
||||
}
|
||||
|
||||
return CursorState.fromViewState(cursor.viewState.move(
|
||||
@@ -229,12 +230,12 @@ export class CursorMoveCommands {
|
||||
}
|
||||
}
|
||||
|
||||
public static word(context: CursorContext, cursor: CursorState, inSelectionMode: boolean, _position: IPosition): PartialCursorState {
|
||||
const position = context.model.validatePosition(_position);
|
||||
return CursorState.fromModelState(WordOperations.word(context.config, context.model, cursor.modelState, inSelectionMode, position));
|
||||
public static word(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition): PartialCursorState {
|
||||
const position = viewModel.model.validatePosition(_position);
|
||||
return CursorState.fromModelState(WordOperations.word(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, position));
|
||||
}
|
||||
|
||||
public static cancelSelection(context: CursorContext, cursor: CursorState): PartialCursorState {
|
||||
public static cancelSelection(viewModel: IViewModel, cursor: CursorState): PartialCursorState {
|
||||
if (!cursor.modelState.hasSelection()) {
|
||||
return new CursorState(cursor.modelState, cursor.viewState);
|
||||
}
|
||||
@@ -248,108 +249,107 @@ export class CursorMoveCommands {
|
||||
));
|
||||
}
|
||||
|
||||
public static moveTo(context: CursorContext, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {
|
||||
const position = context.model.validatePosition(_position);
|
||||
public static moveTo(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState {
|
||||
const position = viewModel.model.validatePosition(_position);
|
||||
const viewPosition = (
|
||||
_viewPosition
|
||||
? context.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)
|
||||
: context.convertModelPositionToViewPosition(position)
|
||||
? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)
|
||||
: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)
|
||||
);
|
||||
return CursorState.fromViewState(cursor.viewState.move(inSelectionMode, viewPosition.lineNumber, viewPosition.column, 0));
|
||||
}
|
||||
|
||||
public static move(context: CursorContext, cursors: CursorState[], args: CursorMove.ParsedArguments): PartialCursorState[] | null {
|
||||
const inSelectionMode = args.select;
|
||||
const value = args.value;
|
||||
|
||||
switch (args.direction) {
|
||||
public static simpleMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.SimpleMoveDirection, inSelectionMode: boolean, value: number, unit: CursorMove.Unit): PartialCursorState[] | null {
|
||||
switch (direction) {
|
||||
case CursorMove.Direction.Left: {
|
||||
if (args.unit === CursorMove.Unit.HalfLine) {
|
||||
if (unit === CursorMove.Unit.HalfLine) {
|
||||
// Move left by half the current line length
|
||||
return this._moveHalfLineLeft(context, cursors, inSelectionMode);
|
||||
return this._moveHalfLineLeft(viewModel, cursors, inSelectionMode);
|
||||
} else {
|
||||
// Move left by `moveParams.value` columns
|
||||
return this._moveLeft(context, cursors, inSelectionMode, value);
|
||||
return this._moveLeft(viewModel, cursors, inSelectionMode, value);
|
||||
}
|
||||
}
|
||||
case CursorMove.Direction.Right: {
|
||||
if (args.unit === CursorMove.Unit.HalfLine) {
|
||||
if (unit === CursorMove.Unit.HalfLine) {
|
||||
// Move right by half the current line length
|
||||
return this._moveHalfLineRight(context, cursors, inSelectionMode);
|
||||
return this._moveHalfLineRight(viewModel, cursors, inSelectionMode);
|
||||
} else {
|
||||
// Move right by `moveParams.value` columns
|
||||
return this._moveRight(context, cursors, inSelectionMode, value);
|
||||
return this._moveRight(viewModel, cursors, inSelectionMode, value);
|
||||
}
|
||||
}
|
||||
case CursorMove.Direction.Up: {
|
||||
if (args.unit === CursorMove.Unit.WrappedLine) {
|
||||
if (unit === CursorMove.Unit.WrappedLine) {
|
||||
// Move up by view lines
|
||||
return this._moveUpByViewLines(context, cursors, inSelectionMode, value);
|
||||
return this._moveUpByViewLines(viewModel, cursors, inSelectionMode, value);
|
||||
} else {
|
||||
// Move up by model lines
|
||||
return this._moveUpByModelLines(context, cursors, inSelectionMode, value);
|
||||
return this._moveUpByModelLines(viewModel, cursors, inSelectionMode, value);
|
||||
}
|
||||
}
|
||||
case CursorMove.Direction.Down: {
|
||||
if (args.unit === CursorMove.Unit.WrappedLine) {
|
||||
if (unit === CursorMove.Unit.WrappedLine) {
|
||||
// Move down by view lines
|
||||
return this._moveDownByViewLines(context, cursors, inSelectionMode, value);
|
||||
return this._moveDownByViewLines(viewModel, cursors, inSelectionMode, value);
|
||||
} else {
|
||||
// Move down by model lines
|
||||
return this._moveDownByModelLines(context, cursors, inSelectionMode, value);
|
||||
return this._moveDownByModelLines(viewModel, cursors, inSelectionMode, value);
|
||||
}
|
||||
}
|
||||
case CursorMove.Direction.WrappedLineStart: {
|
||||
// Move to the beginning of the current view line
|
||||
return this._moveToViewMinColumn(context, cursors, inSelectionMode);
|
||||
return this._moveToViewMinColumn(viewModel, cursors, inSelectionMode);
|
||||
}
|
||||
case CursorMove.Direction.WrappedLineFirstNonWhitespaceCharacter: {
|
||||
// Move to the first non-whitespace column of the current view line
|
||||
return this._moveToViewFirstNonWhitespaceColumn(context, cursors, inSelectionMode);
|
||||
return this._moveToViewFirstNonWhitespaceColumn(viewModel, cursors, inSelectionMode);
|
||||
}
|
||||
case CursorMove.Direction.WrappedLineColumnCenter: {
|
||||
// Move to the "center" of the current view line
|
||||
return this._moveToViewCenterColumn(context, cursors, inSelectionMode);
|
||||
return this._moveToViewCenterColumn(viewModel, cursors, inSelectionMode);
|
||||
}
|
||||
case CursorMove.Direction.WrappedLineEnd: {
|
||||
// Move to the end of the current view line
|
||||
return this._moveToViewMaxColumn(context, cursors, inSelectionMode);
|
||||
return this._moveToViewMaxColumn(viewModel, cursors, inSelectionMode);
|
||||
}
|
||||
case CursorMove.Direction.WrappedLineLastNonWhitespaceCharacter: {
|
||||
// Move to the last non-whitespace column of the current view line
|
||||
return this._moveToViewLastNonWhitespaceColumn(context, cursors, inSelectionMode);
|
||||
return this._moveToViewLastNonWhitespaceColumn(viewModel, cursors, inSelectionMode);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static viewportMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.ViewportDirection, inSelectionMode: boolean, value: number): PartialCursorState[] | null {
|
||||
const visibleViewRange = viewModel.getCompletelyVisibleViewRange();
|
||||
const visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);
|
||||
switch (direction) {
|
||||
case CursorMove.Direction.ViewPortTop: {
|
||||
// Move to the nth line start in the viewport (from the top)
|
||||
const cursor = cursors[0];
|
||||
const visibleModelRange = context.getCompletelyVisibleModelRange();
|
||||
const modelLineNumber = this._firstLineNumberInRange(context.model, visibleModelRange, value);
|
||||
const modelColumn = context.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(context, cursor, inSelectionMode, modelLineNumber, modelColumn)];
|
||||
const modelLineNumber = this._firstLineNumberInRange(viewModel.model, visibleModelRange, value);
|
||||
const modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];
|
||||
}
|
||||
case CursorMove.Direction.ViewPortBottom: {
|
||||
// Move to the nth line start in the viewport (from the bottom)
|
||||
const cursor = cursors[0];
|
||||
const visibleModelRange = context.getCompletelyVisibleModelRange();
|
||||
const modelLineNumber = this._lastLineNumberInRange(context.model, visibleModelRange, value);
|
||||
const modelColumn = context.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(context, cursor, inSelectionMode, modelLineNumber, modelColumn)];
|
||||
const modelLineNumber = this._lastLineNumberInRange(viewModel.model, visibleModelRange, value);
|
||||
const modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];
|
||||
}
|
||||
case CursorMove.Direction.ViewPortCenter: {
|
||||
// Move to the line start in the viewport center
|
||||
const cursor = cursors[0];
|
||||
const visibleModelRange = context.getCompletelyVisibleModelRange();
|
||||
const modelLineNumber = Math.round((visibleModelRange.startLineNumber + visibleModelRange.endLineNumber) / 2);
|
||||
const modelColumn = context.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(context, cursor, inSelectionMode, modelLineNumber, modelColumn)];
|
||||
const modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);
|
||||
return [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];
|
||||
}
|
||||
case CursorMove.Direction.ViewPortIfOutside: {
|
||||
// Move to a position inside the viewport
|
||||
const visibleViewRange = context.getCompletelyVisibleViewRange();
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = this.findPositionInViewportIfOutside(context, cursor, visibleViewRange, inSelectionMode);
|
||||
result[i] = this.findPositionInViewportIfOutside(viewModel, cursor, visibleViewRange, inSelectionMode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -358,8 +358,7 @@ export class CursorMoveCommands {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static findPositionInViewportIfOutside(context: CursorContext, cursor: CursorState, visibleViewRange: Range, inSelectionMode: boolean): PartialCursorState {
|
||||
public static findPositionInViewportIfOutside(viewModel: IViewModel, cursor: CursorState, visibleViewRange: Range, inSelectionMode: boolean): PartialCursorState {
|
||||
let viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
|
||||
if (visibleViewRange.startLineNumber <= viewLineNumber && viewLineNumber <= visibleViewRange.endLineNumber - 1) {
|
||||
@@ -373,8 +372,8 @@ export class CursorMoveCommands {
|
||||
if (viewLineNumber < visibleViewRange.startLineNumber) {
|
||||
viewLineNumber = visibleViewRange.startLineNumber;
|
||||
}
|
||||
const viewColumn = context.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);
|
||||
return this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);
|
||||
return this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,19 +403,19 @@ export class CursorMoveCommands {
|
||||
return Math.max(startLineNumber, range.endLineNumber - count + 1);
|
||||
}
|
||||
|
||||
private static _moveLeft(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
private static _moveLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
|
||||
let newViewState = MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
let newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
if (!cursor.viewState.hasSelection() && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
|
||||
// moved over to the previous view line
|
||||
const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
|
||||
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
|
||||
newViewState = MoveOperations.moveLeft(context.config, context.viewModel, newViewState, inSelectionMode, 1);
|
||||
newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,29 +424,29 @@ export class CursorMoveCommands {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveHalfLineLeft(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveHalfLineLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const halfLine = Math.round(context.viewModel.getLineContent(viewLineNumber).length / 2);
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, halfLine));
|
||||
const halfLine = Math.round(viewModel.getLineContent(viewLineNumber).length / 2);
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveRight(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
private static _moveRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
let newViewState = MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
let newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns);
|
||||
|
||||
if (!cursor.viewState.hasSelection() && noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
|
||||
// moved over to the next view line
|
||||
const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
|
||||
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
|
||||
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
|
||||
newViewState = MoveOperations.moveRight(context.config, context.viewModel, newViewState, inSelectionMode, 1);
|
||||
newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,112 +455,112 @@ export class CursorMoveCommands {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveHalfLineRight(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveHalfLineRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const halfLine = Math.round(context.viewModel.getLineContent(viewLineNumber).length / 2);
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, halfLine));
|
||||
const halfLine = Math.round(viewModel.getLineContent(viewLineNumber).length / 2);
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveDownByViewLines(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
private static _moveDownByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveDown(context.config, context.viewModel, cursor.viewState, inSelectionMode, linesCount));
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveDownByModelLines(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
private static _moveDownByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveDown(context.config, context.model, cursor.modelState, inSelectionMode, linesCount));
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveUpByViewLines(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
private static _moveUpByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveUp(context.config, context.viewModel, cursor.viewState, inSelectionMode, linesCount));
|
||||
result[i] = CursorState.fromViewState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveUpByModelLines(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
private static _moveUpByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveUp(context.config, context.model, cursor.modelState, inSelectionMode, linesCount));
|
||||
result[i] = CursorState.fromModelState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToViewPosition(context: CursorContext, cursor: CursorState, inSelectionMode: boolean, toViewLineNumber: number, toViewColumn: number): PartialCursorState {
|
||||
private static _moveToViewPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toViewLineNumber: number, toViewColumn: number): PartialCursorState {
|
||||
return CursorState.fromViewState(cursor.viewState.move(inSelectionMode, toViewLineNumber, toViewColumn, 0));
|
||||
}
|
||||
|
||||
private static _moveToModelPosition(context: CursorContext, cursor: CursorState, inSelectionMode: boolean, toModelLineNumber: number, toModelColumn: number): PartialCursorState {
|
||||
private static _moveToModelPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toModelLineNumber: number, toModelColumn: number): PartialCursorState {
|
||||
return CursorState.fromModelState(cursor.modelState.move(inSelectionMode, toModelLineNumber, toModelColumn, 0));
|
||||
}
|
||||
|
||||
private static _moveToViewMinColumn(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveToViewMinColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const viewColumn = context.viewModel.getLineMinColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = viewModel.getLineMinColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToViewFirstNonWhitespaceColumn(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveToViewFirstNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const viewColumn = context.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToViewCenterColumn(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveToViewCenterColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const viewColumn = Math.round((context.viewModel.getLineMaxColumn(viewLineNumber) + context.viewModel.getLineMinColumn(viewLineNumber)) / 2);
|
||||
result[i] = this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = Math.round((viewModel.getLineMaxColumn(viewLineNumber) + viewModel.getLineMinColumn(viewLineNumber)) / 2);
|
||||
result[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToViewMaxColumn(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveToViewMaxColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const viewColumn = context.viewModel.getLineMaxColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = viewModel.getLineMaxColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _moveToViewLastNonWhitespaceColumn(context: CursorContext, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
private static _moveToViewLastNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {
|
||||
let result: PartialCursorState[] = [];
|
||||
for (let i = 0, len = cursors.length; i < len; i++) {
|
||||
const cursor = cursors[i];
|
||||
const viewLineNumber = cursor.viewState.position.lineNumber;
|
||||
const viewColumn = context.viewModel.getLineLastNonWhitespaceColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(context, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
const viewColumn = viewModel.getLineLastNonWhitespaceColumn(viewLineNumber);
|
||||
result[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -767,6 +766,13 @@ export namespace CursorMove {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface SimpleMoveArguments {
|
||||
direction: SimpleMoveDirection;
|
||||
unit: Unit;
|
||||
select: boolean;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export const enum Direction {
|
||||
Left,
|
||||
Right,
|
||||
@@ -786,6 +792,25 @@ export namespace CursorMove {
|
||||
ViewPortIfOutside,
|
||||
}
|
||||
|
||||
export type SimpleMoveDirection = (
|
||||
Direction.Left
|
||||
| Direction.Right
|
||||
| Direction.Up
|
||||
| Direction.Down
|
||||
| Direction.WrappedLineStart
|
||||
| Direction.WrappedLineFirstNonWhitespaceCharacter
|
||||
| Direction.WrappedLineColumnCenter
|
||||
| Direction.WrappedLineEnd
|
||||
| Direction.WrappedLineLastNonWhitespaceCharacter
|
||||
);
|
||||
|
||||
export type ViewportDirection = (
|
||||
Direction.ViewPortTop
|
||||
| Direction.ViewPortCenter
|
||||
| Direction.ViewPortBottom
|
||||
| Direction.ViewPortIfOutside
|
||||
);
|
||||
|
||||
export const enum Unit {
|
||||
None,
|
||||
Line,
|
||||
|
||||
@@ -81,11 +81,11 @@ export class OneCursor {
|
||||
}
|
||||
// We only have the view state => compute the model state
|
||||
const selectionStart = context.model.validateRange(
|
||||
context.convertViewRangeToModelRange(viewState.selectionStart)
|
||||
context.coordinatesConverter.convertViewRangeToModelRange(viewState.selectionStart)
|
||||
);
|
||||
|
||||
const position = context.model.validatePosition(
|
||||
context.convertViewPositionToModelPosition(viewState.position.lineNumber, viewState.position.column)
|
||||
context.coordinatesConverter.convertViewPositionToModelPosition(viewState.position)
|
||||
);
|
||||
|
||||
modelState = new SingleCursorState(selectionStart, viewState.selectionStartLeftoverVisibleColumns, position, viewState.leftoverVisibleColumns);
|
||||
@@ -104,15 +104,15 @@ export class OneCursor {
|
||||
|
||||
if (!viewState) {
|
||||
// We only have the model state => compute the view state
|
||||
const viewSelectionStart1 = context.convertModelPositionToViewPosition(new Position(modelState.selectionStart.startLineNumber, modelState.selectionStart.startColumn));
|
||||
const viewSelectionStart2 = context.convertModelPositionToViewPosition(new Position(modelState.selectionStart.endLineNumber, modelState.selectionStart.endColumn));
|
||||
const viewSelectionStart1 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.startLineNumber, modelState.selectionStart.startColumn));
|
||||
const viewSelectionStart2 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.endLineNumber, modelState.selectionStart.endColumn));
|
||||
const viewSelectionStart = new Range(viewSelectionStart1.lineNumber, viewSelectionStart1.column, viewSelectionStart2.lineNumber, viewSelectionStart2.column);
|
||||
const viewPosition = context.convertModelPositionToViewPosition(modelState.position);
|
||||
const viewPosition = context.coordinatesConverter.convertModelPositionToViewPosition(modelState.position);
|
||||
viewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);
|
||||
} else {
|
||||
// Validate new view state
|
||||
const viewSelectionStart = context.validateViewRange(viewState.selectionStart, modelState.selectionStart);
|
||||
const viewPosition = context.validateViewPosition(viewState.position, modelState.position);
|
||||
const viewSelectionStart = context.coordinatesConverter.validateViewRange(viewState.selectionStart, modelState.selectionStart);
|
||||
const viewPosition = context.coordinatesConverter.validateViewPosition(viewState.position, modelState.position);
|
||||
viewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);
|
||||
}
|
||||
|
||||
|
||||
@@ -150,6 +150,7 @@ export interface ILineChange extends IChange {
|
||||
* @internal
|
||||
*/
|
||||
export interface IConfiguration extends IDisposable {
|
||||
onDidChangeFast(listener: (e: ConfigurationChangedEvent) => void): IDisposable;
|
||||
onDidChange(listener: (e: ConfigurationChangedEvent) => void): IDisposable;
|
||||
|
||||
readonly options: IComputedEditorOptions;
|
||||
@@ -480,7 +481,7 @@ export interface IEditor {
|
||||
* @param handlerId The id of the handler or the id of a contribution.
|
||||
* @param payload Extra data to be sent to the handler.
|
||||
*/
|
||||
trigger(source: string, handlerId: string, payload: any): void;
|
||||
trigger(source: string | null | undefined, handlerId: string, payload: any): void;
|
||||
|
||||
/**
|
||||
* Gets the current model attached to this editor.
|
||||
@@ -688,14 +689,36 @@ export const EditorType = {
|
||||
* Built-in commands.
|
||||
* @internal
|
||||
*/
|
||||
export const Handler = {
|
||||
ExecuteCommand: 'executeCommand',
|
||||
ExecuteCommands: 'executeCommands',
|
||||
export const enum Handler {
|
||||
CompositionStart = 'compositionStart',
|
||||
CompositionEnd = 'compositionEnd',
|
||||
Type = 'type',
|
||||
ReplacePreviousChar = 'replacePreviousChar',
|
||||
Paste = 'paste',
|
||||
Cut = 'cut',
|
||||
}
|
||||
|
||||
Type: 'type',
|
||||
ReplacePreviousChar: 'replacePreviousChar',
|
||||
CompositionStart: 'compositionStart',
|
||||
CompositionEnd: 'compositionEnd',
|
||||
Paste: 'paste',
|
||||
Cut: 'cut',
|
||||
};
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface TypePayload {
|
||||
text: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface ReplacePreviousCharPayload {
|
||||
text: string;
|
||||
replaceCharCnt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface PastePayload {
|
||||
text: string;
|
||||
pasteOnNewLine: boolean;
|
||||
multicursorText: string[] | null;
|
||||
mode: string | null;
|
||||
}
|
||||
|
||||
@@ -551,6 +551,18 @@ export interface ITextModel {
|
||||
*/
|
||||
mightContainRTL(): boolean;
|
||||
|
||||
/**
|
||||
* If true, the text model might contain LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS), NEXT LINE (NEL).
|
||||
* If false, the text model definitely does not contain these.
|
||||
* @internal
|
||||
*/
|
||||
mightContainUnusualLineTerminators(): boolean;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
removeUnusualLineTerminators(selections?: Selection[]): void;
|
||||
|
||||
/**
|
||||
* If true, the text model might contain non basic ASCII.
|
||||
* If false, the text model **contains only** basic ASCII.
|
||||
@@ -1281,6 +1293,8 @@ export interface IReadonlyTextBuffer {
|
||||
onDidChangeContent: Event<void>;
|
||||
equals(other: ITextBuffer): boolean;
|
||||
mightContainRTL(): boolean;
|
||||
mightContainUnusualLineTerminators(): boolean;
|
||||
resetMightContainUnusualLineTerminators(): void;
|
||||
mightContainNonBasicASCII(): boolean;
|
||||
getBOM(): string;
|
||||
getEOL(): string;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IUndoRedoService, IResourceUndoRedoElement, UndoRedoElementType, IWorks
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TextChange, compressConsecutiveTextChanges } from 'vs/editor/common/model/textChange';
|
||||
import * as buffer from 'vs/base/common/buffer';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
function uriGetComparisonKey(resource: URI): string {
|
||||
return resource.toString();
|
||||
@@ -138,6 +139,10 @@ class SingleModelEditStackData {
|
||||
}
|
||||
}
|
||||
|
||||
export interface IUndoRedoDelegate {
|
||||
prepareUndoRedo(element: MultiModelEditStackElement): Promise<IDisposable> | IDisposable | void;
|
||||
}
|
||||
|
||||
export class SingleModelEditStackElement implements IResourceUndoRedoElement {
|
||||
|
||||
public model: ITextModel | URI;
|
||||
@@ -224,6 +229,8 @@ export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
|
||||
private readonly _editStackElementsArr: SingleModelEditStackElement[];
|
||||
private readonly _editStackElementsMap: Map<string, SingleModelEditStackElement>;
|
||||
|
||||
private _delegate: IUndoRedoDelegate | null;
|
||||
|
||||
public get resources(): readonly URI[] {
|
||||
return this._editStackElementsArr.map(editStackElement => editStackElement.resource);
|
||||
}
|
||||
@@ -240,6 +247,27 @@ export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
|
||||
const key = uriGetComparisonKey(editStackElement.resource);
|
||||
this._editStackElementsMap.set(key, editStackElement);
|
||||
}
|
||||
this._delegate = null;
|
||||
}
|
||||
|
||||
public setDelegate(delegate: IUndoRedoDelegate): void {
|
||||
this._delegate = delegate;
|
||||
}
|
||||
|
||||
public prepareUndoRedo(): Promise<IDisposable> | IDisposable | void {
|
||||
if (this._delegate) {
|
||||
return this._delegate.prepareUndoRedo(this);
|
||||
}
|
||||
}
|
||||
|
||||
public getMissingModels(): URI[] {
|
||||
const result: URI[] = [];
|
||||
for (const editStackElement of this._editStackElementsArr) {
|
||||
if (URI.isUri(editStackElement.model)) {
|
||||
result.push(editStackElement.model);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public setModel(model: ITextModel | URI): void {
|
||||
|
||||
@@ -36,15 +36,17 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
private readonly _pieceTree: PieceTreeBase;
|
||||
private readonly _BOM: string;
|
||||
private _mightContainRTL: boolean;
|
||||
private _mightContainUnusualLineTerminators: boolean;
|
||||
private _mightContainNonBasicASCII: boolean;
|
||||
|
||||
private readonly _onDidChangeContent: Emitter<void> = new Emitter<void>();
|
||||
public readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
|
||||
|
||||
constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, isBasicASCII: boolean, eolNormalized: boolean) {
|
||||
constructor(chunks: StringBuffer[], BOM: string, eol: '\r\n' | '\n', containsRTL: boolean, containsUnusualLineTerminators: boolean, isBasicASCII: boolean, eolNormalized: boolean) {
|
||||
this._BOM = BOM;
|
||||
this._mightContainNonBasicASCII = !isBasicASCII;
|
||||
this._mightContainRTL = containsRTL;
|
||||
this._mightContainUnusualLineTerminators = containsUnusualLineTerminators;
|
||||
this._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);
|
||||
}
|
||||
dispose(): void {
|
||||
@@ -67,6 +69,12 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
public mightContainRTL(): boolean {
|
||||
return this._mightContainRTL;
|
||||
}
|
||||
public mightContainUnusualLineTerminators(): boolean {
|
||||
return this._mightContainUnusualLineTerminators;
|
||||
}
|
||||
public resetMightContainUnusualLineTerminators(): void {
|
||||
this._mightContainUnusualLineTerminators = false;
|
||||
}
|
||||
public mightContainNonBasicASCII(): boolean {
|
||||
return this._mightContainNonBasicASCII;
|
||||
}
|
||||
@@ -216,6 +224,7 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
|
||||
public applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult {
|
||||
let mightContainRTL = this._mightContainRTL;
|
||||
let mightContainUnusualLineTerminators = this._mightContainUnusualLineTerminators;
|
||||
let mightContainNonBasicASCII = this._mightContainNonBasicASCII;
|
||||
let canReduceOperations = true;
|
||||
|
||||
@@ -226,12 +235,20 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
canReduceOperations = false;
|
||||
}
|
||||
let validatedRange = op.range;
|
||||
if (!mightContainRTL && op.text) {
|
||||
// check if the new inserted text contains RTL
|
||||
mightContainRTL = strings.containsRTL(op.text);
|
||||
}
|
||||
if (!mightContainNonBasicASCII && op.text) {
|
||||
mightContainNonBasicASCII = !strings.isBasicASCII(op.text);
|
||||
if (op.text) {
|
||||
let textMightContainNonBasicASCII = true;
|
||||
if (!mightContainNonBasicASCII) {
|
||||
textMightContainNonBasicASCII = !strings.isBasicASCII(op.text);
|
||||
mightContainNonBasicASCII = textMightContainNonBasicASCII;
|
||||
}
|
||||
if (!mightContainRTL && textMightContainNonBasicASCII) {
|
||||
// check if the new inserted text contains RTL
|
||||
mightContainRTL = strings.containsRTL(op.text);
|
||||
}
|
||||
if (!mightContainUnusualLineTerminators && textMightContainNonBasicASCII) {
|
||||
// check if the new inserted text contains unusual line terminators
|
||||
mightContainUnusualLineTerminators = strings.containsUnusualLineTerminators(op.text);
|
||||
}
|
||||
}
|
||||
|
||||
let validText = '';
|
||||
@@ -340,6 +357,7 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
|
||||
|
||||
this._mightContainRTL = mightContainRTL;
|
||||
this._mightContainUnusualLineTerminators = mightContainUnusualLineTerminators;
|
||||
this._mightContainNonBasicASCII = mightContainNonBasicASCII;
|
||||
|
||||
const contentChanges = this._doApplyEdits(operations);
|
||||
|
||||
@@ -18,6 +18,7 @@ export class PieceTreeTextBufferFactory implements ITextBufferFactory {
|
||||
private readonly _lf: number,
|
||||
private readonly _crlf: number,
|
||||
private readonly _containsRTL: boolean,
|
||||
private readonly _containsUnusualLineTerminators: boolean,
|
||||
private readonly _isBasicASCII: boolean,
|
||||
private readonly _normalizeEOL: boolean
|
||||
) { }
|
||||
@@ -53,7 +54,7 @@ export class PieceTreeTextBufferFactory implements ITextBufferFactory {
|
||||
}
|
||||
}
|
||||
|
||||
return new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._isBasicASCII, this._normalizeEOL);
|
||||
return new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);
|
||||
}
|
||||
|
||||
public getFirstLineText(lengthLimit: number): string {
|
||||
@@ -73,6 +74,7 @@ export class PieceTreeTextBufferBuilder implements ITextBufferBuilder {
|
||||
private lf: number;
|
||||
private crlf: number;
|
||||
private containsRTL: boolean;
|
||||
private containsUnusualLineTerminators: boolean;
|
||||
private isBasicASCII: boolean;
|
||||
|
||||
constructor() {
|
||||
@@ -87,6 +89,7 @@ export class PieceTreeTextBufferBuilder implements ITextBufferBuilder {
|
||||
this.lf = 0;
|
||||
this.crlf = 0;
|
||||
this.containsRTL = false;
|
||||
this.containsUnusualLineTerminators = false;
|
||||
this.isBasicASCII = true;
|
||||
}
|
||||
|
||||
@@ -140,9 +143,13 @@ export class PieceTreeTextBufferBuilder implements ITextBufferBuilder {
|
||||
this.isBasicASCII = lineStarts.isBasicASCII;
|
||||
}
|
||||
if (!this.isBasicASCII && !this.containsRTL) {
|
||||
// No need to check if is basic ASCII
|
||||
// No need to check if it is basic ASCII
|
||||
this.containsRTL = strings.containsRTL(chunk);
|
||||
}
|
||||
if (!this.isBasicASCII && !this.containsUnusualLineTerminators) {
|
||||
// No need to check if it is basic ASCII
|
||||
this.containsUnusualLineTerminators = strings.containsUnusualLineTerminators(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public finish(normalizeEOL: boolean = true): PieceTreeTextBufferFactory {
|
||||
@@ -154,6 +161,7 @@ export class PieceTreeTextBufferBuilder implements ITextBufferBuilder {
|
||||
this.lf,
|
||||
this.crlf,
|
||||
this.containsRTL,
|
||||
this.containsUnusualLineTerminators,
|
||||
this.isBasicASCII,
|
||||
normalizeEOL
|
||||
);
|
||||
|
||||
@@ -37,6 +37,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { EditorTheme } from 'vs/editor/common/view/viewContext';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { TextChange } from 'vs/editor/common/model/textChange';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
|
||||
function createTextBufferBuilder() {
|
||||
return new PieceTreeTextBufferBuilder();
|
||||
@@ -699,6 +700,17 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
return this._buffer.mightContainRTL();
|
||||
}
|
||||
|
||||
public mightContainUnusualLineTerminators(): boolean {
|
||||
return this._buffer.mightContainUnusualLineTerminators();
|
||||
}
|
||||
|
||||
public removeUnusualLineTerminators(selections: Selection[] | null = null): void {
|
||||
const matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
const eol = this.getEOL();
|
||||
this._buffer.resetMightContainUnusualLineTerminators();
|
||||
this.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: eol })), () => null);
|
||||
}
|
||||
|
||||
public mightContainNonBasicASCII(): boolean {
|
||||
return this._buffer.mightContainNonBasicASCII();
|
||||
}
|
||||
@@ -1097,7 +1109,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
||||
return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
|
||||
}
|
||||
|
||||
public findMatches(searchString: string, rawSearchScope: any, isRegex: boolean, matchCase: boolean, wordSeparators: string, captureMatches: boolean, limitResultCount: number = LIMIT_FIND_COUNT): model.FindMatch[] {
|
||||
public findMatches(searchString: string, rawSearchScope: any, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount: number = LIMIT_FIND_COUNT): model.FindMatch[] {
|
||||
this._assertNotDisposed();
|
||||
|
||||
let searchRange: Range;
|
||||
|
||||
@@ -1411,11 +1411,12 @@ export interface RenameProvider {
|
||||
*/
|
||||
export interface AuthenticationSession {
|
||||
id: string;
|
||||
getAccessToken(): Thenable<string>;
|
||||
accessToken: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
}
|
||||
scopes: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1602,7 +1603,7 @@ export interface IWebviewPortMapping {
|
||||
export interface IWebviewOptions {
|
||||
readonly enableScripts?: boolean;
|
||||
readonly enableCommandUris?: boolean;
|
||||
readonly localResourceRoots?: ReadonlyArray<URI>;
|
||||
readonly localResourceRoots?: ReadonlyArray<UriComponents>;
|
||||
readonly portMapping?: ReadonlyArray<IWebviewPortMapping>;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens
|
||||
break;
|
||||
|
||||
case CharCode.UTF8_BOM:
|
||||
case CharCode.LINE_SEPARATOR_2028:
|
||||
case CharCode.LINE_SEPARATOR:
|
||||
case CharCode.PARAGRAPH_SEPARATOR:
|
||||
case CharCode.NEXT_LINE:
|
||||
partContent += '\ufffd';
|
||||
break;
|
||||
|
||||
|
||||
@@ -113,12 +113,12 @@ interface IRawConfig {
|
||||
|
||||
const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF;
|
||||
|
||||
interface EditStackPastFutureElements {
|
||||
export interface EditStackPastFutureElements {
|
||||
past: EditStackElement[];
|
||||
future: EditStackElement[];
|
||||
}
|
||||
|
||||
function isEditStackPastFutureElements(undoElements: IPastFutureElements): undoElements is EditStackPastFutureElements {
|
||||
export function isEditStackPastFutureElements(undoElements: IPastFutureElements): undoElements is EditStackPastFutureElements {
|
||||
return (isEditStackElements(undoElements.past) && isEditStackElements(undoElements.future));
|
||||
}
|
||||
|
||||
|
||||
66
src/vs/editor/common/services/modelUndoRedoParticipant.ts
Normal file
66
src/vs/editor/common/services/modelUndoRedoParticipant.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { isEditStackPastFutureElements } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { IUndoRedoDelegate, MultiModelEditStackElement } from 'vs/editor/common/model/editStack';
|
||||
|
||||
export class ModelUndoRedoParticipant extends Disposable implements IUndoRedoDelegate {
|
||||
constructor(
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@ITextModelService private readonly _textModelService: ITextModelService,
|
||||
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
|
||||
) {
|
||||
super();
|
||||
this._register(this._modelService.onModelRemoved((model) => {
|
||||
// a model will get disposed, so let's check if the undo redo stack is maintained
|
||||
const elements = this._undoRedoService.getElements(model.uri);
|
||||
if (elements.past.length === 0 && elements.future.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!isEditStackPastFutureElements(elements)) {
|
||||
return;
|
||||
}
|
||||
for (const element of elements.past) {
|
||||
if (element.type === UndoRedoElementType.Workspace) {
|
||||
element.setDelegate(this);
|
||||
}
|
||||
}
|
||||
for (const element of elements.future) {
|
||||
if (element.type === UndoRedoElementType.Workspace) {
|
||||
element.setDelegate(this);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public prepareUndoRedo(element: MultiModelEditStackElement): IDisposable | Promise<IDisposable> {
|
||||
// Load all the needed text models
|
||||
const missingModels = element.getMissingModels();
|
||||
if (missingModels.length === 0) {
|
||||
// All models are available!
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
const disposablesPromises = missingModels.map(async (uri) => {
|
||||
try {
|
||||
const reference = await this._textModelService.createModelReference(uri);
|
||||
return <IDisposable>reference;
|
||||
} catch (err) {
|
||||
// This model could not be loaded, maybe it was deleted in the meantime?
|
||||
return Disposable.None;
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(disposablesPromises).then(disposables => {
|
||||
return {
|
||||
dispose: () => dispose(disposables)
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,9 @@ export interface ITextModelService {
|
||||
registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable;
|
||||
|
||||
/**
|
||||
* Check if a provider for the given `scheme` exists
|
||||
* Check if the given resource can be resolved to a text model.
|
||||
*/
|
||||
hasTextModelContentProvider(scheme: string): boolean;
|
||||
canHandleResource(resource: URI): boolean;
|
||||
}
|
||||
|
||||
export interface ITextModelContentProvider {
|
||||
|
||||
@@ -240,49 +240,50 @@ export enum EditorOption {
|
||||
quickSuggestions = 70,
|
||||
quickSuggestionsDelay = 71,
|
||||
readOnly = 72,
|
||||
renameOnType = 73,
|
||||
renderControlCharacters = 74,
|
||||
renderIndentGuides = 75,
|
||||
renderFinalNewline = 76,
|
||||
renderLineHighlight = 77,
|
||||
renderLineHighlightOnlyWhenFocus = 78,
|
||||
renderValidationDecorations = 79,
|
||||
renderWhitespace = 80,
|
||||
revealHorizontalRightPadding = 81,
|
||||
roundedSelection = 82,
|
||||
rulers = 83,
|
||||
scrollbar = 84,
|
||||
scrollBeyondLastColumn = 85,
|
||||
scrollBeyondLastLine = 86,
|
||||
scrollPredominantAxis = 87,
|
||||
selectionClipboard = 88,
|
||||
selectionHighlight = 89,
|
||||
selectOnLineNumbers = 90,
|
||||
showFoldingControls = 91,
|
||||
showUnused = 92,
|
||||
snippetSuggestions = 93,
|
||||
smoothScrolling = 94,
|
||||
stopRenderingLineAfter = 95,
|
||||
suggest = 96,
|
||||
suggestFontSize = 97,
|
||||
suggestLineHeight = 98,
|
||||
suggestOnTriggerCharacters = 99,
|
||||
suggestSelection = 100,
|
||||
tabCompletion = 101,
|
||||
useTabStops = 102,
|
||||
wordSeparators = 103,
|
||||
wordWrap = 104,
|
||||
wordWrapBreakAfterCharacters = 105,
|
||||
wordWrapBreakBeforeCharacters = 106,
|
||||
wordWrapColumn = 107,
|
||||
wordWrapMinified = 108,
|
||||
wrappingIndent = 109,
|
||||
wrappingStrategy = 110,
|
||||
editorClassName = 111,
|
||||
pixelRatio = 112,
|
||||
tabFocusMode = 113,
|
||||
layoutInfo = 114,
|
||||
wrappingInfo = 115
|
||||
removeUnusualLineTerminators = 73,
|
||||
renameOnType = 74,
|
||||
renderControlCharacters = 75,
|
||||
renderIndentGuides = 76,
|
||||
renderFinalNewline = 77,
|
||||
renderLineHighlight = 78,
|
||||
renderLineHighlightOnlyWhenFocus = 79,
|
||||
renderValidationDecorations = 80,
|
||||
renderWhitespace = 81,
|
||||
revealHorizontalRightPadding = 82,
|
||||
roundedSelection = 83,
|
||||
rulers = 84,
|
||||
scrollbar = 85,
|
||||
scrollBeyondLastColumn = 86,
|
||||
scrollBeyondLastLine = 87,
|
||||
scrollPredominantAxis = 88,
|
||||
selectionClipboard = 89,
|
||||
selectionHighlight = 90,
|
||||
selectOnLineNumbers = 91,
|
||||
showFoldingControls = 92,
|
||||
showUnused = 93,
|
||||
snippetSuggestions = 94,
|
||||
smoothScrolling = 95,
|
||||
stopRenderingLineAfter = 96,
|
||||
suggest = 97,
|
||||
suggestFontSize = 98,
|
||||
suggestLineHeight = 99,
|
||||
suggestOnTriggerCharacters = 100,
|
||||
suggestSelection = 101,
|
||||
tabCompletion = 102,
|
||||
useTabStops = 103,
|
||||
wordSeparators = 104,
|
||||
wordWrap = 105,
|
||||
wordWrapBreakAfterCharacters = 106,
|
||||
wordWrapBreakBeforeCharacters = 107,
|
||||
wordWrapColumn = 108,
|
||||
wordWrapMinified = 109,
|
||||
wrappingIndent = 110,
|
||||
wrappingStrategy = 111,
|
||||
editorClassName = 112,
|
||||
pixelRatio = 113,
|
||||
tabFocusMode = 114,
|
||||
layoutInfo = 115,
|
||||
wrappingInfo = 116
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
||||
import { ViewEventDispatcher } from 'vs/editor/common/view/viewEventDispatcher';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
import { IViewLayout, IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { IColorTheme, ThemeType } from 'vs/platform/theme/common/themeService';
|
||||
@@ -37,27 +36,24 @@ export class ViewContext {
|
||||
public readonly configuration: IConfiguration;
|
||||
public readonly model: IViewModel;
|
||||
public readonly viewLayout: IViewLayout;
|
||||
public readonly privateViewEventBus: ViewEventDispatcher;
|
||||
public readonly theme: EditorTheme;
|
||||
|
||||
constructor(
|
||||
configuration: IConfiguration,
|
||||
theme: IColorTheme,
|
||||
model: IViewModel,
|
||||
privateViewEventBus: ViewEventDispatcher
|
||||
model: IViewModel
|
||||
) {
|
||||
this.configuration = configuration;
|
||||
this.theme = new EditorTheme(theme);
|
||||
this.model = model;
|
||||
this.viewLayout = model.viewLayout;
|
||||
this.privateViewEventBus = privateViewEventBus;
|
||||
}
|
||||
|
||||
public addEventHandler(eventHandler: ViewEventHandler): void {
|
||||
this.privateViewEventBus.addEventHandler(eventHandler);
|
||||
this.model.addViewEventHandler(eventHandler);
|
||||
}
|
||||
|
||||
public removeEventHandler(eventHandler: ViewEventHandler): void {
|
||||
this.privateViewEventBus.removeEventHandler(eventHandler);
|
||||
this.model.removeViewEventHandler(eventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ViewEvent } from 'vs/editor/common/view/viewEvents';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
|
||||
export class ViewEventDispatcher {
|
||||
|
||||
private readonly _eventHandlerGateKeeper: (callback: () => void) => void;
|
||||
private readonly _eventHandlers: ViewEventHandler[];
|
||||
private _eventQueue: ViewEvent[] | null;
|
||||
private _isConsumingQueue: boolean;
|
||||
|
||||
constructor(eventHandlerGateKeeper: (callback: () => void) => void) {
|
||||
this._eventHandlerGateKeeper = eventHandlerGateKeeper;
|
||||
this._eventHandlers = [];
|
||||
this._eventQueue = null;
|
||||
this._isConsumingQueue = false;
|
||||
}
|
||||
|
||||
public addEventHandler(eventHandler: ViewEventHandler): void {
|
||||
for (let i = 0, len = this._eventHandlers.length; i < len; i++) {
|
||||
if (this._eventHandlers[i] === eventHandler) {
|
||||
console.warn('Detected duplicate listener in ViewEventDispatcher', eventHandler);
|
||||
}
|
||||
}
|
||||
this._eventHandlers.push(eventHandler);
|
||||
}
|
||||
|
||||
public removeEventHandler(eventHandler: ViewEventHandler): void {
|
||||
for (let i = 0; i < this._eventHandlers.length; i++) {
|
||||
if (this._eventHandlers[i] === eventHandler) {
|
||||
this._eventHandlers.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public emit(event: ViewEvent): void {
|
||||
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(event);
|
||||
} else {
|
||||
this._eventQueue = [event];
|
||||
}
|
||||
|
||||
if (!this._isConsumingQueue) {
|
||||
this.consumeQueue();
|
||||
}
|
||||
}
|
||||
|
||||
public emitMany(events: ViewEvent[]): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue = this._eventQueue.concat(events);
|
||||
} else {
|
||||
this._eventQueue = events;
|
||||
}
|
||||
|
||||
if (!this._isConsumingQueue) {
|
||||
this.consumeQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private consumeQueue(): void {
|
||||
this._eventHandlerGateKeeper(() => {
|
||||
try {
|
||||
this._isConsumingQueue = true;
|
||||
|
||||
this._doConsumeQueue();
|
||||
|
||||
} finally {
|
||||
this._isConsumingQueue = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _doConsumeQueue(): void {
|
||||
while (this._eventQueue) {
|
||||
// Empty event queue, as events might come in while sending these off
|
||||
let events = this._eventQueue;
|
||||
this._eventQueue = null;
|
||||
|
||||
// Use a clone of the event handlers list, as they might remove themselves
|
||||
let eventHandlers = this._eventHandlers.slice(0);
|
||||
for (let i = 0, len = eventHandlers.length; i < len; i++) {
|
||||
eventHandlers[i].handleEvents(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,30 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ScrollEvent } from 'vs/base/common/scrollable';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ScrollType, IContentSizeChangedEvent } from 'vs/editor/common/editorCommon';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
|
||||
export const enum ViewEventType {
|
||||
ViewConfigurationChanged = 1,
|
||||
ViewContentSizeChanged = 2,
|
||||
ViewCursorStateChanged = 3,
|
||||
ViewDecorationsChanged = 4,
|
||||
ViewFlushed = 5,
|
||||
ViewFocusChanged = 6,
|
||||
ViewLanguageConfigurationChanged = 7,
|
||||
ViewLineMappingChanged = 8,
|
||||
ViewLinesChanged = 9,
|
||||
ViewLinesDeleted = 10,
|
||||
ViewLinesInserted = 11,
|
||||
ViewRevealRangeRequest = 12,
|
||||
ViewScrollChanged = 13,
|
||||
ViewThemeChanged = 14,
|
||||
ViewTokensChanged = 15,
|
||||
ViewTokensColorsChanged = 16,
|
||||
ViewZonesChanged = 17,
|
||||
ViewConfigurationChanged,
|
||||
ViewCursorStateChanged,
|
||||
ViewDecorationsChanged,
|
||||
ViewFlushed,
|
||||
ViewFocusChanged,
|
||||
ViewLanguageConfigurationChanged,
|
||||
ViewLineMappingChanged,
|
||||
ViewLinesChanged,
|
||||
ViewLinesDeleted,
|
||||
ViewLinesInserted,
|
||||
ViewRevealRangeRequest,
|
||||
ViewScrollChanged,
|
||||
ViewThemeChanged,
|
||||
ViewTokensChanged,
|
||||
ViewTokensColorsChanged,
|
||||
ViewZonesChanged,
|
||||
}
|
||||
|
||||
export class ViewConfigurationChangedEvent {
|
||||
@@ -47,25 +44,6 @@ export class ViewConfigurationChangedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewContentSizeChangedEvent implements IContentSizeChangedEvent {
|
||||
|
||||
public readonly type = ViewEventType.ViewContentSizeChanged;
|
||||
|
||||
public readonly contentWidth: number;
|
||||
public readonly contentHeight: number;
|
||||
|
||||
public readonly contentWidthChanged: boolean;
|
||||
public readonly contentHeightChanged: boolean;
|
||||
|
||||
constructor(source: IContentSizeChangedEvent) {
|
||||
this.contentWidth = source.contentWidth;
|
||||
this.contentHeight = source.contentHeight;
|
||||
|
||||
this.contentWidthChanged = source.contentWidthChanged;
|
||||
this.contentHeightChanged = source.contentHeightChanged;
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewCursorStateChangedEvent {
|
||||
|
||||
public readonly type = ViewEventType.ViewCursorStateChanged;
|
||||
@@ -224,9 +202,9 @@ export class ViewRevealRangeRequestEvent {
|
||||
/**
|
||||
* Source of the call that caused the event.
|
||||
*/
|
||||
readonly source: string;
|
||||
readonly source: string | null | undefined;
|
||||
|
||||
constructor(source: string, range: Range | null, selections: Selection[] | null, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) {
|
||||
constructor(source: string | null | undefined, range: Range | null, selections: Selection[] | null, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: ScrollType) {
|
||||
this.source = source;
|
||||
this.range = range;
|
||||
this.selections = selections;
|
||||
@@ -308,7 +286,6 @@ export class ViewZonesChangedEvent {
|
||||
|
||||
export type ViewEvent = (
|
||||
ViewConfigurationChangedEvent
|
||||
| ViewContentSizeChangedEvent
|
||||
| ViewCursorStateChangedEvent
|
||||
| ViewDecorationsChangedEvent
|
||||
| ViewFlushedEvent
|
||||
@@ -325,94 +302,3 @@ export type ViewEvent = (
|
||||
| ViewTokensColorsChangedEvent
|
||||
| ViewZonesChangedEvent
|
||||
);
|
||||
|
||||
export interface IViewEventListener {
|
||||
(events: ViewEvent[]): void;
|
||||
}
|
||||
|
||||
export class ViewEventEmitter extends Disposable {
|
||||
private _listeners: IViewEventListener[];
|
||||
private _collector: ViewEventsCollector | null;
|
||||
private _collectorCnt: number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._listeners = [];
|
||||
this._collector = null;
|
||||
this._collectorCnt = 0;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._listeners = [];
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
protected _beginEmit(): ViewEventsCollector {
|
||||
this._collectorCnt++;
|
||||
if (this._collectorCnt === 1) {
|
||||
this._collector = new ViewEventsCollector();
|
||||
}
|
||||
return this._collector!;
|
||||
}
|
||||
|
||||
protected _endEmit(): void {
|
||||
this._collectorCnt--;
|
||||
if (this._collectorCnt === 0) {
|
||||
const events = this._collector!.finalize();
|
||||
this._collector = null;
|
||||
if (events.length > 0) {
|
||||
this._emit(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _emit(events: ViewEvent[]): void {
|
||||
const listeners = this._listeners.slice(0);
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
safeInvokeListener(listeners[i], events);
|
||||
}
|
||||
}
|
||||
|
||||
public addEventListener(listener: (events: ViewEvent[]) => void): IDisposable {
|
||||
this._listeners.push(listener);
|
||||
return toDisposable(() => {
|
||||
let listeners = this._listeners;
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
if (listeners[i] === listener) {
|
||||
listeners.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewEventsCollector {
|
||||
|
||||
private _events: ViewEvent[];
|
||||
private _eventsLen = 0;
|
||||
|
||||
constructor() {
|
||||
this._events = [];
|
||||
this._eventsLen = 0;
|
||||
}
|
||||
|
||||
public emit(event: ViewEvent) {
|
||||
this._events[this._eventsLen++] = event;
|
||||
}
|
||||
|
||||
public finalize(): ViewEvent[] {
|
||||
let result = this._events;
|
||||
this._events = [];
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function safeInvokeListener(listener: IViewEventListener, events: ViewEvent[]): void {
|
||||
try {
|
||||
listener(events);
|
||||
} catch (e) {
|
||||
errors.onUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,33 +180,36 @@ export class LinesLayout {
|
||||
this._lineCount = lineCount;
|
||||
}
|
||||
|
||||
public changeWhitespace<T>(callback: (accessor: IWhitespaceChangeAccessor) => T): T {
|
||||
public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {
|
||||
let hadAChange = false;
|
||||
try {
|
||||
const accessor = {
|
||||
const accessor: IWhitespaceChangeAccessor = {
|
||||
insertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => {
|
||||
hadAChange = true;
|
||||
afterLineNumber = afterLineNumber | 0;
|
||||
ordinal = ordinal | 0;
|
||||
heightInPx = heightInPx | 0;
|
||||
minWidth = minWidth | 0;
|
||||
|
||||
const id = this._instanceId + (++this._lastWhitespaceId);
|
||||
this._pendingChanges.insert(new EditorWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth));
|
||||
return id;
|
||||
},
|
||||
changeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): void => {
|
||||
hadAChange = true;
|
||||
newAfterLineNumber = newAfterLineNumber | 0;
|
||||
newHeight = newHeight | 0;
|
||||
|
||||
this._pendingChanges.change({ id, newAfterLineNumber, newHeight });
|
||||
},
|
||||
removeWhitespace: (id: string): void => {
|
||||
hadAChange = true;
|
||||
this._pendingChanges.remove({ id });
|
||||
}
|
||||
};
|
||||
return callback(accessor);
|
||||
callback(accessor);
|
||||
} finally {
|
||||
this._pendingChanges.commit(this);
|
||||
}
|
||||
return hadAChange;
|
||||
}
|
||||
|
||||
public _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void {
|
||||
|
||||
@@ -7,10 +7,11 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility, INewScrollPosition } from 'vs/base/common/scrollable';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IConfiguration, IContentSizeChangedEvent } from 'vs/editor/common/editorCommon';
|
||||
import { IConfiguration, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { LinesLayout, IEditorWhitespace, IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';
|
||||
import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
||||
import { IViewLayout, IViewWhitespaceViewportData, Viewport } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { ContentSizeChangedEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher';
|
||||
|
||||
const SMOOTH_SCROLLING_TIME = 125;
|
||||
|
||||
@@ -75,8 +76,8 @@ class EditorScrollable extends Disposable {
|
||||
|
||||
public readonly onDidScroll: Event<ScrollEvent>;
|
||||
|
||||
private readonly _onDidContentSizeChange = this._register(new Emitter<IContentSizeChangedEvent>());
|
||||
public readonly onDidContentSizeChange: Event<IContentSizeChangedEvent> = this._onDidContentSizeChange.event;
|
||||
private readonly _onDidContentSizeChange = this._register(new Emitter<ContentSizeChangedEvent>());
|
||||
public readonly onDidContentSizeChange: Event<ContentSizeChangedEvent> = this._onDidContentSizeChange.event;
|
||||
|
||||
constructor(smoothScrollDuration: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {
|
||||
super();
|
||||
@@ -119,13 +120,10 @@ class EditorScrollable extends Disposable {
|
||||
const contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);
|
||||
const contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);
|
||||
if (contentWidthChanged || contentHeightChanged) {
|
||||
this._onDidContentSizeChange.fire({
|
||||
contentWidth: dimensions.contentWidth,
|
||||
contentHeight: dimensions.contentHeight,
|
||||
|
||||
contentWidthChanged: contentWidthChanged,
|
||||
contentHeightChanged: contentHeightChanged
|
||||
});
|
||||
this._onDidContentSizeChange.fire(new ContentSizeChangedEvent(
|
||||
oldDimensions.contentWidth, oldDimensions.contentHeight,
|
||||
dimensions.contentWidth, dimensions.contentHeight
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +151,7 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
|
||||
private readonly _scrollable: EditorScrollable;
|
||||
public readonly onDidScroll: Event<ScrollEvent>;
|
||||
public readonly onDidContentSizeChange: Event<IContentSizeChangedEvent>;
|
||||
public readonly onDidContentSizeChange: Event<ContentSizeChangedEvent>;
|
||||
|
||||
constructor(configuration: IConfiguration, lineCount: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {
|
||||
super();
|
||||
@@ -324,7 +322,7 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public onMaxLineWidthChanged(maxLineWidth: number): void {
|
||||
public setMaxLineWidth(maxLineWidth: number): void {
|
||||
const scrollDimensions = this._scrollable.getScrollDimensions();
|
||||
// const newScrollWidth = ;
|
||||
this._scrollable.setScrollDimensions(new EditorScrollDimensions(
|
||||
@@ -353,8 +351,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
}
|
||||
|
||||
// ---- IVerticalLayoutProvider
|
||||
public changeWhitespace<T>(callback: (accessor: IWhitespaceChangeAccessor) => T): T {
|
||||
return this._linesLayout.changeWhitespace(callback);
|
||||
public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {
|
||||
const hadAChange = this._linesLayout.changeWhitespace(callback);
|
||||
if (hadAChange) {
|
||||
this.onHeightMaybeChanged();
|
||||
}
|
||||
return hadAChange;
|
||||
}
|
||||
public getVerticalOffsetForLineNumber(lineNumber: number): number {
|
||||
return this._linesLayout.getVerticalOffsetForLineNumber(lineNumber);
|
||||
@@ -424,12 +426,12 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
return this._scrollable.validateScrollPosition(scrollPosition);
|
||||
}
|
||||
|
||||
public setScrollPositionNow(position: INewScrollPosition): void {
|
||||
this._scrollable.setScrollPositionNow(position);
|
||||
}
|
||||
|
||||
public setScrollPositionSmooth(position: INewScrollPosition): void {
|
||||
this._scrollable.setScrollPositionSmooth(position);
|
||||
public setScrollPosition(position: INewScrollPosition, type: ScrollType): void {
|
||||
if (type === ScrollType.Immediate) {
|
||||
this._scrollable.setScrollPositionNow(position);
|
||||
} else {
|
||||
this._scrollable.setScrollPositionSmooth(position);
|
||||
}
|
||||
}
|
||||
|
||||
public deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void {
|
||||
|
||||
@@ -934,7 +934,9 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
||||
break;
|
||||
|
||||
case CharCode.UTF8_BOM:
|
||||
case CharCode.LINE_SEPARATOR_2028:
|
||||
case CharCode.LINE_SEPARATOR:
|
||||
case CharCode.PARAGRAPH_SEPARATOR:
|
||||
case CharCode.NEXT_LINE:
|
||||
sb.write1(0xFFFD);
|
||||
break;
|
||||
|
||||
|
||||
@@ -36,9 +36,7 @@ export class ViewEventHandler extends Disposable {
|
||||
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
|
||||
return false;
|
||||
}
|
||||
public onContentSizeChanged(e: viewEvents.ViewContentSizeChangedEvent): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
|
||||
return false;
|
||||
}
|
||||
@@ -102,12 +100,6 @@ export class ViewEventHandler extends Disposable {
|
||||
}
|
||||
break;
|
||||
|
||||
case viewEvents.ViewEventType.ViewContentSizeChanged:
|
||||
if (this.onContentSizeChanged(e)) {
|
||||
shouldRender = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case viewEvents.ViewEventType.ViewCursorStateChanged:
|
||||
if (this.onCursorStateChanged(e)) {
|
||||
shouldRender = true;
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IScrollPosition, Scrollable } from 'vs/base/common/scrollable';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IViewLineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { INewScrollPosition } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { IViewEventListener } from 'vs/editor/common/view/viewEvents';
|
||||
import { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, IModelDecorationOptions, TextModelResolvedOptions, ITextModel } from 'vs/editor/common/model';
|
||||
import { VerticalRevealType } 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 { ICursorSimpleModel, PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
|
||||
export interface IViewWhitespaceViewportData {
|
||||
readonly id: string;
|
||||
@@ -43,8 +45,6 @@ export interface IViewLayout {
|
||||
|
||||
getScrollable(): Scrollable;
|
||||
|
||||
onMaxLineWidthChanged(width: number): void;
|
||||
|
||||
getScrollWidth(): number;
|
||||
getScrollHeight(): number;
|
||||
|
||||
@@ -55,9 +55,6 @@ export interface IViewLayout {
|
||||
getFutureViewport(): Viewport;
|
||||
|
||||
validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition;
|
||||
setScrollPositionNow(position: INewScrollPosition): void;
|
||||
setScrollPositionSmooth(position: INewScrollPosition): void;
|
||||
deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void;
|
||||
|
||||
getLinesViewportData(): IPartialViewLinesViewportData;
|
||||
getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData;
|
||||
@@ -68,18 +65,10 @@ export interface IViewLayout {
|
||||
getVerticalOffsetForLineNumber(lineNumber: number): number;
|
||||
getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null;
|
||||
|
||||
// --------------- Begin vertical whitespace management
|
||||
changeWhitespace<T>(callback: (accessor: IWhitespaceChangeAccessor) => T): T;
|
||||
|
||||
/**
|
||||
* Get the layout information for whitespaces currently in the viewport
|
||||
*/
|
||||
getWhitespaceViewportData(): IViewWhitespaceViewportData[];
|
||||
|
||||
// TODO@Alex whitespace management should work via a change accessor sort of thing
|
||||
onHeightMaybeChanged(): void;
|
||||
|
||||
// --------------- End vertical whitespace management
|
||||
}
|
||||
|
||||
export interface ICoordinatesConverter {
|
||||
@@ -95,20 +84,26 @@ export interface ICoordinatesConverter {
|
||||
modelPositionIsVisible(modelPosition: Position): boolean;
|
||||
}
|
||||
|
||||
export interface IViewModel {
|
||||
export interface IViewModel extends ICursorSimpleModel {
|
||||
|
||||
addEventListener(listener: IViewEventListener): IDisposable;
|
||||
readonly model: ITextModel;
|
||||
|
||||
readonly coordinatesConverter: ICoordinatesConverter;
|
||||
|
||||
readonly viewLayout: IViewLayout;
|
||||
|
||||
readonly cursorConfig: CursorConfiguration;
|
||||
|
||||
addViewEventHandler(eventHandler: ViewEventHandler): void;
|
||||
removeViewEventHandler(eventHandler: ViewEventHandler): void;
|
||||
|
||||
/**
|
||||
* Gives a hint that a lot of requests are about to come in for these line numbers.
|
||||
*/
|
||||
setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void;
|
||||
tokenizeViewport(): void;
|
||||
setHasFocus(hasFocus: boolean): void;
|
||||
onDidColorThemeChange(): void;
|
||||
|
||||
getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];
|
||||
getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;
|
||||
@@ -117,7 +112,7 @@ export interface IViewModel {
|
||||
getCompletelyVisibleViewRange(): Range;
|
||||
getCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range;
|
||||
|
||||
getOptions(): TextModelResolvedOptions;
|
||||
getTextModelOptions(): TextModelResolvedOptions;
|
||||
getLineCount(): number;
|
||||
getLineContent(lineNumber: number): string;
|
||||
getLineLength(lineNumber: number): number;
|
||||
@@ -140,6 +135,38 @@ export interface IViewModel {
|
||||
getEOL(): string;
|
||||
getPlainTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean, forceCRLF: boolean): string | string[];
|
||||
getRichTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean): { html: string, mode: string } | null;
|
||||
|
||||
//#region model
|
||||
|
||||
pushStackElement(): void;
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
//#region cursor
|
||||
getPrimaryCursorState(): CursorState;
|
||||
getLastAddedCursorIndex(): number;
|
||||
getCursorStates(): CursorState[];
|
||||
setCursorStates(source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): void;
|
||||
getCursorColumnSelectData(): IColumnSelectData;
|
||||
setCursorColumnSelectData(columnSelectData: IColumnSelectData): void;
|
||||
getPrevEditOperationType(): EditOperationType;
|
||||
setPrevEditOperationType(type: EditOperationType): void;
|
||||
revealPrimaryCursor(source: string | null | undefined, revealHorizontal: boolean): void;
|
||||
revealTopMostCursor(source: string | null | undefined): void;
|
||||
revealBottomMostCursor(source: string | null | undefined): void;
|
||||
revealRange(source: string | null | undefined, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void;
|
||||
//#endregion
|
||||
|
||||
//#region viewLayout
|
||||
getVerticalOffsetForLineNumber(viewLineNumber: number): number;
|
||||
getScrollTop(): number;
|
||||
setScrollTop(newScrollTop: number, scrollType: ScrollType): void;
|
||||
setScrollPosition(position: INewScrollPosition, type: ScrollType): void;
|
||||
deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void;
|
||||
changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): void;
|
||||
setMaxLineWidth(maxLineWidth: number): void;
|
||||
//#endregion
|
||||
}
|
||||
|
||||
export class MinimapLinesRenderingData {
|
||||
|
||||
393
src/vs/editor/common/viewModel/viewModelEventDispatcher.ts
Normal file
393
src/vs/editor/common/viewModel/viewModelEventDispatcher.ts
Normal file
@@ -0,0 +1,393 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
import { ViewEvent } from 'vs/editor/common/view/viewEvents';
|
||||
import { IContentSizeChangedEvent } from 'vs/editor/common/editorCommon';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
|
||||
export class ViewModelEventDispatcher extends Disposable {
|
||||
|
||||
private readonly _onEvent = this._register(new Emitter<OutgoingViewModelEvent>());
|
||||
public readonly onEvent = this._onEvent.event;
|
||||
|
||||
private readonly _eventHandlers: ViewEventHandler[];
|
||||
private _viewEventQueue: ViewEvent[] | null;
|
||||
private _isConsumingViewEventQueue: boolean;
|
||||
private _collector: ViewModelEventsCollector | null;
|
||||
private _collectorCnt: number;
|
||||
private _outgoingEvents: OutgoingViewModelEvent[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._eventHandlers = [];
|
||||
this._viewEventQueue = null;
|
||||
this._isConsumingViewEventQueue = false;
|
||||
this._collector = null;
|
||||
this._collectorCnt = 0;
|
||||
this._outgoingEvents = [];
|
||||
}
|
||||
|
||||
public emitOutgoingEvent(e: OutgoingViewModelEvent): void {
|
||||
this._addOutgoingEvent(e);
|
||||
this._emitOugoingEvents();
|
||||
}
|
||||
|
||||
private _addOutgoingEvent(e: OutgoingViewModelEvent): void {
|
||||
for (let i = 0, len = this._outgoingEvents.length; i < len; i++) {
|
||||
if (this._outgoingEvents[i].kind === e.kind) {
|
||||
this._outgoingEvents[i] = this._outgoingEvents[i].merge(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// not merged
|
||||
this._outgoingEvents.push(e);
|
||||
}
|
||||
|
||||
private _emitOugoingEvents(): void {
|
||||
while (this._outgoingEvents.length > 0) {
|
||||
if (this._collector || this._isConsumingViewEventQueue) {
|
||||
// right now collecting or emitting view events, so let's postpone emitting
|
||||
return;
|
||||
}
|
||||
const event = this._outgoingEvents.shift()!;
|
||||
if (event.isNoOp()) {
|
||||
continue;
|
||||
}
|
||||
this._onEvent.fire(event);
|
||||
}
|
||||
}
|
||||
|
||||
public addViewEventHandler(eventHandler: ViewEventHandler): void {
|
||||
for (let i = 0, len = this._eventHandlers.length; i < len; i++) {
|
||||
if (this._eventHandlers[i] === eventHandler) {
|
||||
console.warn('Detected duplicate listener in ViewEventDispatcher', eventHandler);
|
||||
}
|
||||
}
|
||||
this._eventHandlers.push(eventHandler);
|
||||
}
|
||||
|
||||
public removeViewEventHandler(eventHandler: ViewEventHandler): void {
|
||||
for (let i = 0; i < this._eventHandlers.length; i++) {
|
||||
if (this._eventHandlers[i] === eventHandler) {
|
||||
this._eventHandlers.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public beginEmitViewEvents(): ViewModelEventsCollector {
|
||||
this._collectorCnt++;
|
||||
if (this._collectorCnt === 1) {
|
||||
this._collector = new ViewModelEventsCollector();
|
||||
}
|
||||
return this._collector!;
|
||||
}
|
||||
|
||||
public endEmitViewEvents(): void {
|
||||
this._collectorCnt--;
|
||||
if (this._collectorCnt === 0) {
|
||||
const outgoingEvents = this._collector!.outgoingEvents;
|
||||
const viewEvents = this._collector!.viewEvents;
|
||||
this._collector = null;
|
||||
|
||||
for (const outgoingEvent of outgoingEvents) {
|
||||
this._addOutgoingEvent(outgoingEvent);
|
||||
}
|
||||
|
||||
if (viewEvents.length > 0) {
|
||||
this._emitMany(viewEvents);
|
||||
}
|
||||
}
|
||||
this._emitOugoingEvents();
|
||||
}
|
||||
|
||||
public emitSingleViewEvent(event: ViewEvent): void {
|
||||
try {
|
||||
const eventsCollector = this.beginEmitViewEvents();
|
||||
eventsCollector.emitViewEvent(event);
|
||||
} finally {
|
||||
this.endEmitViewEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private _emitMany(events: ViewEvent[]): void {
|
||||
if (this._viewEventQueue) {
|
||||
this._viewEventQueue = this._viewEventQueue.concat(events);
|
||||
} else {
|
||||
this._viewEventQueue = events;
|
||||
}
|
||||
|
||||
if (!this._isConsumingViewEventQueue) {
|
||||
this._consumeViewEventQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private _consumeViewEventQueue(): void {
|
||||
try {
|
||||
this._isConsumingViewEventQueue = true;
|
||||
this._doConsumeQueue();
|
||||
} finally {
|
||||
this._isConsumingViewEventQueue = false;
|
||||
}
|
||||
}
|
||||
|
||||
private _doConsumeQueue(): void {
|
||||
while (this._viewEventQueue) {
|
||||
// Empty event queue, as events might come in while sending these off
|
||||
const events = this._viewEventQueue;
|
||||
this._viewEventQueue = null;
|
||||
|
||||
// Use a clone of the event handlers list, as they might remove themselves
|
||||
const eventHandlers = this._eventHandlers.slice(0);
|
||||
for (const eventHandler of eventHandlers) {
|
||||
eventHandler.handleEvents(events);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewModelEventsCollector {
|
||||
|
||||
public readonly viewEvents: ViewEvent[];
|
||||
public readonly outgoingEvents: OutgoingViewModelEvent[];
|
||||
|
||||
constructor() {
|
||||
this.viewEvents = [];
|
||||
this.outgoingEvents = [];
|
||||
}
|
||||
|
||||
public emitViewEvent(event: ViewEvent) {
|
||||
this.viewEvents.push(event);
|
||||
}
|
||||
|
||||
public emitOutgoingEvent(e: OutgoingViewModelEvent): void {
|
||||
this.outgoingEvents.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
export const enum OutgoingViewModelEventKind {
|
||||
ContentSizeChanged,
|
||||
FocusChanged,
|
||||
ScrollChanged,
|
||||
ViewZonesChanged,
|
||||
ReadOnlyEditAttempt,
|
||||
CursorStateChanged,
|
||||
}
|
||||
|
||||
export class ContentSizeChangedEvent implements IContentSizeChangedEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.ContentSizeChanged;
|
||||
|
||||
private readonly _oldContentWidth: number;
|
||||
private readonly _oldContentHeight: number;
|
||||
|
||||
readonly contentWidth: number;
|
||||
readonly contentHeight: number;
|
||||
readonly contentWidthChanged: boolean;
|
||||
readonly contentHeightChanged: boolean;
|
||||
|
||||
constructor(oldContentWidth: number, oldContentHeight: number, contentWidth: number, contentHeight: number) {
|
||||
this._oldContentWidth = oldContentWidth;
|
||||
this._oldContentHeight = oldContentHeight;
|
||||
this.contentWidth = contentWidth;
|
||||
this.contentHeight = contentHeight;
|
||||
this.contentWidthChanged = (this._oldContentWidth !== this.contentWidth);
|
||||
this.contentHeightChanged = (this._oldContentHeight !== this.contentHeight);
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return (!this.contentWidthChanged && !this.contentHeightChanged);
|
||||
}
|
||||
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): ContentSizeChangedEvent {
|
||||
if (other.kind !== OutgoingViewModelEventKind.ContentSizeChanged) {
|
||||
return this;
|
||||
}
|
||||
return new ContentSizeChangedEvent(this._oldContentWidth, this._oldContentHeight, other.contentWidth, other.contentHeight);
|
||||
}
|
||||
}
|
||||
|
||||
export class FocusChangedEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.FocusChanged;
|
||||
|
||||
readonly oldHasFocus: boolean;
|
||||
readonly hasFocus: boolean;
|
||||
|
||||
constructor(oldHasFocus: boolean, hasFocus: boolean) {
|
||||
this.oldHasFocus = oldHasFocus;
|
||||
this.hasFocus = hasFocus;
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return (this.oldHasFocus === this.hasFocus);
|
||||
}
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): FocusChangedEvent {
|
||||
if (other.kind !== OutgoingViewModelEventKind.FocusChanged) {
|
||||
return this;
|
||||
}
|
||||
return new FocusChangedEvent(this.oldHasFocus, other.hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
export class ScrollChangedEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.ScrollChanged;
|
||||
|
||||
private readonly _oldScrollWidth: number;
|
||||
private readonly _oldScrollLeft: number;
|
||||
private readonly _oldScrollHeight: number;
|
||||
private readonly _oldScrollTop: number;
|
||||
|
||||
public readonly scrollWidth: number;
|
||||
public readonly scrollLeft: number;
|
||||
public readonly scrollHeight: number;
|
||||
public readonly scrollTop: number;
|
||||
|
||||
public readonly scrollWidthChanged: boolean;
|
||||
public readonly scrollLeftChanged: boolean;
|
||||
public readonly scrollHeightChanged: boolean;
|
||||
public readonly scrollTopChanged: boolean;
|
||||
|
||||
constructor(
|
||||
oldScrollWidth: number, oldScrollLeft: number, oldScrollHeight: number, oldScrollTop: number,
|
||||
scrollWidth: number, scrollLeft: number, scrollHeight: number, scrollTop: number,
|
||||
) {
|
||||
this._oldScrollWidth = oldScrollWidth;
|
||||
this._oldScrollLeft = oldScrollLeft;
|
||||
this._oldScrollHeight = oldScrollHeight;
|
||||
this._oldScrollTop = oldScrollTop;
|
||||
|
||||
this.scrollWidth = scrollWidth;
|
||||
this.scrollLeft = scrollLeft;
|
||||
this.scrollHeight = scrollHeight;
|
||||
this.scrollTop = scrollTop;
|
||||
|
||||
this.scrollWidthChanged = (this._oldScrollWidth !== this.scrollWidth);
|
||||
this.scrollLeftChanged = (this._oldScrollLeft !== this.scrollLeft);
|
||||
this.scrollHeightChanged = (this._oldScrollHeight !== this.scrollHeight);
|
||||
this.scrollTopChanged = (this._oldScrollTop !== this.scrollTop);
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return (!this.scrollWidthChanged && !this.scrollLeftChanged && !this.scrollHeightChanged && !this.scrollTopChanged);
|
||||
}
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): ScrollChangedEvent {
|
||||
if (other.kind !== OutgoingViewModelEventKind.ScrollChanged) {
|
||||
return this;
|
||||
}
|
||||
return new ScrollChangedEvent(
|
||||
this._oldScrollWidth, this._oldScrollLeft, this._oldScrollHeight, this._oldScrollTop,
|
||||
other.scrollWidth, other.scrollLeft, other.scrollHeight, other.scrollTop
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewZonesChangedEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.ViewZonesChanged;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): ViewZonesChangedEvent {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class CursorStateChangedEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.CursorStateChanged;
|
||||
|
||||
public readonly oldSelections: Selection[] | null;
|
||||
public readonly selections: Selection[];
|
||||
public readonly oldModelVersionId: number;
|
||||
public readonly modelVersionId: number;
|
||||
public readonly source: string;
|
||||
public readonly reason: CursorChangeReason;
|
||||
public readonly reachedMaxCursorCount: boolean;
|
||||
|
||||
constructor(oldSelections: Selection[] | null, selections: Selection[], oldModelVersionId: number, modelVersionId: number, source: string, reason: CursorChangeReason, reachedMaxCursorCount: boolean) {
|
||||
this.oldSelections = oldSelections;
|
||||
this.selections = selections;
|
||||
this.oldModelVersionId = oldModelVersionId;
|
||||
this.modelVersionId = modelVersionId;
|
||||
this.source = source;
|
||||
this.reason = reason;
|
||||
this.reachedMaxCursorCount = reachedMaxCursorCount;
|
||||
}
|
||||
|
||||
private static _selectionsAreEqual(a: Selection[] | null, b: Selection[] | null): boolean {
|
||||
if (!a && !b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
const aLen = a.length;
|
||||
const bLen = b.length;
|
||||
if (aLen !== bLen) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < aLen; i++) {
|
||||
if (!a[i].equalsSelection(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return (
|
||||
CursorStateChangedEvent._selectionsAreEqual(this.oldSelections, this.selections)
|
||||
&& this.oldModelVersionId === this.modelVersionId
|
||||
);
|
||||
}
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): CursorStateChangedEvent {
|
||||
if (other.kind !== OutgoingViewModelEventKind.CursorStateChanged) {
|
||||
return this;
|
||||
}
|
||||
return new CursorStateChangedEvent(
|
||||
this.oldSelections, other.selections, this.oldModelVersionId, other.modelVersionId, other.source, other.reason, this.reachedMaxCursorCount || other.reachedMaxCursorCount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReadOnlyEditAttemptEvent {
|
||||
|
||||
public readonly kind = OutgoingViewModelEventKind.ReadOnlyEditAttempt;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public isNoOp(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public merge(other: OutgoingViewModelEvent): ReadOnlyEditAttemptEvent {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export type OutgoingViewModelEvent = (
|
||||
ContentSizeChangedEvent
|
||||
| FocusChangedEvent
|
||||
| ScrollChangedEvent
|
||||
| ViewZonesChangedEvent
|
||||
| ReadOnlyEditAttemptEvent
|
||||
| CursorStateChangedEvent
|
||||
);
|
||||
@@ -4,13 +4,15 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ConfigurationChangedEvent, EDITOR_FONT_DEFAULTS, EditorOption, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { IConfiguration, IViewState } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { IConfiguration, IViewState, ScrollType, ICursorState, ICommand, INewScrollPosition } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions, IIdentifiedSingleEditOperation, ICursorStateComputer } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
||||
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
|
||||
import { ColorId, LanguageId, TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
@@ -24,24 +26,34 @@ 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 { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { PartialCursorState, CursorState, IColumnSelectData, EditOperationType, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IWhitespaceChangeAccessor } from 'vs/editor/common/viewLayout/linesLayout';
|
||||
import { ViewModelEventDispatcher, OutgoingViewModelEvent, FocusChangedEvent, ScrollChangedEvent, ViewZonesChangedEvent, ViewModelEventsCollector, ReadOnlyEditAttemptEvent } from 'vs/editor/common/viewModel/viewModelEventDispatcher';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
|
||||
const USE_IDENTITY_LINES_COLLECTION = true;
|
||||
|
||||
export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel {
|
||||
export class ViewModel extends Disposable implements IViewModel {
|
||||
|
||||
private readonly editorId: number;
|
||||
private readonly configuration: IConfiguration;
|
||||
private readonly model: ITextModel;
|
||||
private readonly _editorId: number;
|
||||
private readonly _configuration: IConfiguration;
|
||||
public readonly model: ITextModel;
|
||||
private readonly _eventDispatcher: ViewModelEventDispatcher;
|
||||
public readonly onEvent: Event<OutgoingViewModelEvent>;
|
||||
public cursorConfig: CursorConfiguration;
|
||||
private readonly _tokenizeViewportSoon: RunOnceScheduler;
|
||||
private readonly _updateConfigurationViewLineCount: RunOnceScheduler;
|
||||
private hasFocus: boolean;
|
||||
private viewportStartLine: number;
|
||||
private viewportStartLineTrackedRange: string | null;
|
||||
private viewportStartLineDelta: number;
|
||||
private readonly lines: IViewModelLinesCollection;
|
||||
private _hasFocus: boolean;
|
||||
private _viewportStartLine: number;
|
||||
private _viewportStartLineTrackedRange: string | null;
|
||||
private _viewportStartLineDelta: number;
|
||||
private readonly _lines: IViewModelLinesCollection;
|
||||
public readonly coordinatesConverter: ICoordinatesConverter;
|
||||
public readonly viewLayout: ViewLayout;
|
||||
private readonly decorations: ViewModelDecorations;
|
||||
private readonly _cursor: Cursor;
|
||||
private readonly _decorations: ViewModelDecorations;
|
||||
|
||||
constructor(
|
||||
editorId: number,
|
||||
@@ -53,28 +65,31 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
) {
|
||||
super();
|
||||
|
||||
this.editorId = editorId;
|
||||
this.configuration = configuration;
|
||||
this._editorId = editorId;
|
||||
this._configuration = configuration;
|
||||
this.model = model;
|
||||
this._eventDispatcher = new ViewModelEventDispatcher();
|
||||
this.onEvent = this._eventDispatcher.onEvent;
|
||||
this.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);
|
||||
this._tokenizeViewportSoon = this._register(new RunOnceScheduler(() => this.tokenizeViewport(), 50));
|
||||
this._updateConfigurationViewLineCount = this._register(new RunOnceScheduler(() => this._updateConfigurationViewLineCountNow(), 0));
|
||||
this.hasFocus = false;
|
||||
this.viewportStartLine = -1;
|
||||
this.viewportStartLineTrackedRange = null;
|
||||
this.viewportStartLineDelta = 0;
|
||||
this._hasFocus = false;
|
||||
this._viewportStartLine = -1;
|
||||
this._viewportStartLineTrackedRange = null;
|
||||
this._viewportStartLineDelta = 0;
|
||||
|
||||
if (USE_IDENTITY_LINES_COLLECTION && this.model.isTooLargeForTokenization()) {
|
||||
|
||||
this.lines = new IdentityLinesCollection(this.model);
|
||||
this._lines = new IdentityLinesCollection(this.model);
|
||||
|
||||
} else {
|
||||
const options = this.configuration.options;
|
||||
const options = this._configuration.options;
|
||||
const fontInfo = options.get(EditorOption.fontInfo);
|
||||
const wrappingStrategy = options.get(EditorOption.wrappingStrategy);
|
||||
const wrappingInfo = options.get(EditorOption.wrappingInfo);
|
||||
const wrappingIndent = options.get(EditorOption.wrappingIndent);
|
||||
|
||||
this.lines = new SplitLinesCollection(
|
||||
this._lines = new SplitLinesCollection(
|
||||
this.model,
|
||||
domLineBreaksComputerFactory,
|
||||
monospaceLineBreaksComputerFactory,
|
||||
@@ -86,51 +101,42 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
);
|
||||
}
|
||||
|
||||
this.coordinatesConverter = this.lines.createCoordinatesConverter();
|
||||
this.coordinatesConverter = this._lines.createCoordinatesConverter();
|
||||
|
||||
this.viewLayout = this._register(new ViewLayout(this.configuration, this.getLineCount(), scheduleAtNextAnimationFrame));
|
||||
this._cursor = this._register(new Cursor(model, this, this.coordinatesConverter, this.cursorConfig));
|
||||
|
||||
this.viewLayout = this._register(new ViewLayout(this._configuration, this.getLineCount(), scheduleAtNextAnimationFrame));
|
||||
|
||||
this._register(this.viewLayout.onDidScroll((e) => {
|
||||
if (e.scrollTopChanged) {
|
||||
this._tokenizeViewportSoon.schedule();
|
||||
}
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewScrollChangedEvent(e));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewScrollChangedEvent(e));
|
||||
this._eventDispatcher.emitOutgoingEvent(new ScrollChangedEvent(
|
||||
e.oldScrollWidth, e.oldScrollLeft, e.oldScrollHeight, e.oldScrollTop,
|
||||
e.scrollWidth, e.scrollLeft, e.scrollHeight, e.scrollTop
|
||||
));
|
||||
}));
|
||||
|
||||
this._register(this.viewLayout.onDidContentSizeChange((e) => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewContentSizeChangedEvent(e));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._eventDispatcher.emitOutgoingEvent(e);
|
||||
}));
|
||||
|
||||
this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, this.lines, this.coordinatesConverter);
|
||||
this._decorations = new ViewModelDecorations(this._editorId, this.model, this._configuration, this._lines, this.coordinatesConverter);
|
||||
|
||||
this._registerModelEvents();
|
||||
|
||||
this._register(this.configuration.onDidChange((e) => {
|
||||
this._register(this._configuration.onDidChangeFast((e) => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
this._onConfigurationChanged(eventsCollector, e);
|
||||
} finally {
|
||||
this._endEmit();
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(MinimapTokensColorTracker.getInstance().onDidChange(() => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewTokensColorsChangedEvent());
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewTokensColorsChangedEvent());
|
||||
}));
|
||||
|
||||
this._updateConfigurationViewLineCountNow();
|
||||
@@ -140,14 +146,23 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
// First remove listeners, as disposing the lines might end up sending
|
||||
// model decoration changed events ... and we no longer care about them ...
|
||||
super.dispose();
|
||||
this.decorations.dispose();
|
||||
this.lines.dispose();
|
||||
this._decorations.dispose();
|
||||
this._lines.dispose();
|
||||
this.invalidateMinimapColorCache();
|
||||
this.viewportStartLineTrackedRange = this.model._setTrackedRange(this.viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
||||
this._viewportStartLineTrackedRange = this.model._setTrackedRange(this._viewportStartLineTrackedRange, null, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
||||
this._eventDispatcher.dispose();
|
||||
}
|
||||
|
||||
public addViewEventHandler(eventHandler: ViewEventHandler): void {
|
||||
this._eventDispatcher.addViewEventHandler(eventHandler);
|
||||
}
|
||||
|
||||
public removeViewEventHandler(eventHandler: ViewEventHandler): void {
|
||||
this._eventDispatcher.removeViewEventHandler(eventHandler);
|
||||
}
|
||||
|
||||
private _updateConfigurationViewLineCountNow(): void {
|
||||
this.configuration.setViewLineCount(this.lines.getViewLineCount());
|
||||
this._configuration.setViewLineCount(this._lines.getViewLineCount());
|
||||
}
|
||||
|
||||
public tokenizeViewport(): void {
|
||||
@@ -158,30 +173,38 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
|
||||
public setHasFocus(hasFocus: boolean): void {
|
||||
this.hasFocus = hasFocus;
|
||||
this._hasFocus = hasFocus;
|
||||
this._cursor.setHasFocus(hasFocus);
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewFocusChangedEvent(hasFocus));
|
||||
this._eventDispatcher.emitOutgoingEvent(new FocusChangedEvent(!hasFocus, hasFocus));
|
||||
}
|
||||
|
||||
private _onConfigurationChanged(eventsCollector: viewEvents.ViewEventsCollector, e: ConfigurationChangedEvent): void {
|
||||
public onDidColorThemeChange(): void {
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewThemeChangedEvent());
|
||||
}
|
||||
|
||||
private _onConfigurationChanged(eventsCollector: ViewModelEventsCollector, e: ConfigurationChangedEvent): void {
|
||||
|
||||
// We might need to restore the current centered view range, so save it (if available)
|
||||
let previousViewportStartModelPosition: Position | null = null;
|
||||
if (this.viewportStartLine !== -1) {
|
||||
let previousViewportStartViewPosition = new Position(this.viewportStartLine, this.getLineMinColumn(this.viewportStartLine));
|
||||
if (this._viewportStartLine !== -1) {
|
||||
let previousViewportStartViewPosition = new Position(this._viewportStartLine, this.getLineMinColumn(this._viewportStartLine));
|
||||
previousViewportStartModelPosition = this.coordinatesConverter.convertViewPositionToModelPosition(previousViewportStartViewPosition);
|
||||
}
|
||||
let restorePreviousViewportStart = false;
|
||||
|
||||
const options = this.configuration.options;
|
||||
const options = this._configuration.options;
|
||||
const fontInfo = options.get(EditorOption.fontInfo);
|
||||
const wrappingStrategy = options.get(EditorOption.wrappingStrategy);
|
||||
const wrappingInfo = options.get(EditorOption.wrappingInfo);
|
||||
const wrappingIndent = options.get(EditorOption.wrappingIndent);
|
||||
|
||||
if (this.lines.setWrappingSettings(fontInfo, wrappingStrategy, wrappingInfo.wrappingColumn, wrappingIndent)) {
|
||||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.decorations.onLineMappingChanged();
|
||||
if (this._lines.setWrappingSettings(fontInfo, wrappingStrategy, wrappingInfo.wrappingColumn, wrappingIndent)) {
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this._cursor.onLineMappingChanged(eventsCollector);
|
||||
this._decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
|
||||
if (this.viewLayout.getCurrentScrollTop() !== 0) {
|
||||
@@ -194,17 +217,22 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
|
||||
if (e.hasChanged(EditorOption.readOnly)) {
|
||||
// Must read again all decorations due to readOnly filtering
|
||||
this.decorations.reset();
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this._decorations.reset();
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
}
|
||||
|
||||
eventsCollector.emit(new viewEvents.ViewConfigurationChangedEvent(e));
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewConfigurationChangedEvent(e));
|
||||
this.viewLayout.onConfigurationChanged(e);
|
||||
|
||||
if (restorePreviousViewportStart && previousViewportStartModelPosition) {
|
||||
const viewPosition = this.coordinatesConverter.convertModelPositionToViewPosition(previousViewportStartModelPosition);
|
||||
const viewPositionTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
|
||||
this.viewLayout.setScrollPositionNow({ scrollTop: viewPositionTop + this.viewportStartLineDelta });
|
||||
this.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this._viewportStartLineDelta }, ScrollType.Immediate);
|
||||
}
|
||||
|
||||
if (CursorConfiguration.shouldRecreate(e)) {
|
||||
this.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);
|
||||
this._cursor.updateConfiguration(this.cursorConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +240,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
|
||||
this._register(this.model.onDidChangeRawContentFast((e) => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
|
||||
let hadOtherModelChange = false;
|
||||
let hadModelLineChangeThatChangedLineMapping = false;
|
||||
@@ -221,7 +249,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
const versionId = e.versionId;
|
||||
|
||||
// Do a first pass to compute line mappings, and a second pass to actually interpret them
|
||||
const lineBreaksComputer = this.lines.createLineBreaksComputer();
|
||||
const lineBreaksComputer = this._lines.createLineBreaksComputer();
|
||||
for (const change of changes) {
|
||||
switch (change.changeType) {
|
||||
case textModelEvents.RawContentChangedType.LinesInserted: {
|
||||
@@ -243,17 +271,17 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
|
||||
switch (change.changeType) {
|
||||
case textModelEvents.RawContentChangedType.Flush: {
|
||||
this.lines.onModelFlushed();
|
||||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
this.decorations.reset();
|
||||
this._lines.onModelFlushed();
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());
|
||||
this._decorations.reset();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
hadOtherModelChange = true;
|
||||
break;
|
||||
}
|
||||
case textModelEvents.RawContentChangedType.LinesDeleted: {
|
||||
const linesDeletedEvent = this.lines.onModelLinesDeleted(versionId, change.fromLineNumber, change.toLineNumber);
|
||||
const linesDeletedEvent = this._lines.onModelLinesDeleted(versionId, change.fromLineNumber, change.toLineNumber);
|
||||
if (linesDeletedEvent !== null) {
|
||||
eventsCollector.emit(linesDeletedEvent);
|
||||
eventsCollector.emitViewEvent(linesDeletedEvent);
|
||||
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
|
||||
}
|
||||
hadOtherModelChange = true;
|
||||
@@ -263,9 +291,9 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
const insertedLineBreaks = lineBreaks.slice(lineBreaksOffset, lineBreaksOffset + change.detail.length);
|
||||
lineBreaksOffset += change.detail.length;
|
||||
|
||||
const linesInsertedEvent = this.lines.onModelLinesInserted(versionId, change.fromLineNumber, change.toLineNumber, insertedLineBreaks);
|
||||
const linesInsertedEvent = this._lines.onModelLinesInserted(versionId, change.fromLineNumber, change.toLineNumber, insertedLineBreaks);
|
||||
if (linesInsertedEvent !== null) {
|
||||
eventsCollector.emit(linesInsertedEvent);
|
||||
eventsCollector.emitViewEvent(linesInsertedEvent);
|
||||
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
|
||||
}
|
||||
hadOtherModelChange = true;
|
||||
@@ -275,17 +303,17 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
const changedLineBreakData = lineBreaks[lineBreaksOffset];
|
||||
lineBreaksOffset++;
|
||||
|
||||
const [lineMappingChanged, linesChangedEvent, linesInsertedEvent, linesDeletedEvent] = this.lines.onModelLineChanged(versionId, change.lineNumber, changedLineBreakData);
|
||||
const [lineMappingChanged, linesChangedEvent, linesInsertedEvent, linesDeletedEvent] = this._lines.onModelLineChanged(versionId, change.lineNumber, changedLineBreakData);
|
||||
hadModelLineChangeThatChangedLineMapping = lineMappingChanged;
|
||||
if (linesChangedEvent) {
|
||||
eventsCollector.emit(linesChangedEvent);
|
||||
eventsCollector.emitViewEvent(linesChangedEvent);
|
||||
}
|
||||
if (linesInsertedEvent) {
|
||||
eventsCollector.emit(linesInsertedEvent);
|
||||
eventsCollector.emitViewEvent(linesInsertedEvent);
|
||||
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
|
||||
}
|
||||
if (linesDeletedEvent) {
|
||||
eventsCollector.emit(linesDeletedEvent);
|
||||
eventsCollector.emitViewEvent(linesDeletedEvent);
|
||||
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
|
||||
}
|
||||
break;
|
||||
@@ -296,32 +324,40 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
}
|
||||
}
|
||||
this.lines.acceptVersionId(versionId);
|
||||
this._lines.acceptVersionId(versionId);
|
||||
this.viewLayout.onHeightMaybeChanged();
|
||||
|
||||
if (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.decorations.onLineMappingChanged();
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this._cursor.onLineMappingChanged(eventsCollector);
|
||||
this._decorations.onLineMappingChanged();
|
||||
}
|
||||
} finally {
|
||||
this._endEmit();
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
|
||||
// Update the configuration and reset the centered view line
|
||||
this.viewportStartLine = -1;
|
||||
this.configuration.setMaxLineNumber(this.model.getLineCount());
|
||||
this._viewportStartLine = -1;
|
||||
this._configuration.setMaxLineNumber(this.model.getLineCount());
|
||||
this._updateConfigurationViewLineCountNow();
|
||||
|
||||
// Recover viewport
|
||||
if (!this.hasFocus && this.model.getAttachedEditorCount() >= 2 && this.viewportStartLineTrackedRange) {
|
||||
const modelRange = this.model._getTrackedRange(this.viewportStartLineTrackedRange);
|
||||
if (!this._hasFocus && this.model.getAttachedEditorCount() >= 2 && this._viewportStartLineTrackedRange) {
|
||||
const modelRange = this.model._getTrackedRange(this._viewportStartLineTrackedRange);
|
||||
if (modelRange) {
|
||||
const viewPosition = this.coordinatesConverter.convertModelPositionToViewPosition(modelRange.getStartPosition());
|
||||
const viewPositionTop = this.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
|
||||
this.viewLayout.setScrollPositionNow({ scrollTop: viewPositionTop + this.viewportStartLineDelta });
|
||||
this.viewLayout.setScrollPosition({ scrollTop: viewPositionTop + this._viewportStartLineDelta }, ScrollType.Immediate);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
this._cursor.onModelContentChanged(eventsCollector, e);
|
||||
} finally {
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeTokens((e) => {
|
||||
@@ -335,12 +371,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
toLineNumber: viewEndLineNumber
|
||||
};
|
||||
}
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewTokensChangedEvent(viewRanges));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewTokensChangedEvent(viewRanges));
|
||||
|
||||
if (e.tokenizationSupportChanged) {
|
||||
this._tokenizeViewportSoon.schedule();
|
||||
@@ -348,63 +379,65 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeLanguageConfiguration((e) => {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewLanguageConfigurationEvent());
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewLanguageConfigurationEvent());
|
||||
this.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);
|
||||
this._cursor.updateConfiguration(this.cursorConfig);
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeLanguage((e) => {
|
||||
this.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);
|
||||
this._cursor.updateConfiguration(this.cursorConfig);
|
||||
}));
|
||||
|
||||
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.decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
if (this._lines.setTabSize(this.model.getOptions().tabSize)) {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this._cursor.onLineMappingChanged(eventsCollector);
|
||||
this._decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
} finally {
|
||||
this._endEmit();
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
this._updateConfigurationViewLineCount.schedule();
|
||||
}
|
||||
|
||||
this.cursorConfig = new CursorConfiguration(this.model.getLanguageIdentifier(), this.model.getOptions(), this._configuration);
|
||||
this._cursor.updateConfiguration(this.cursorConfig);
|
||||
}));
|
||||
|
||||
this._register(this.model.onDidChangeDecorations((e) => {
|
||||
this.decorations.onModelDecorationsChanged();
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(e));
|
||||
} finally {
|
||||
this._endEmit();
|
||||
}
|
||||
this._decorations.onModelDecorationsChanged();
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewDecorationsChangedEvent(e));
|
||||
}));
|
||||
}
|
||||
|
||||
public setHiddenAreas(ranges: Range[]): void {
|
||||
try {
|
||||
const eventsCollector = this._beginEmit();
|
||||
let lineMappingChanged = this.lines.setHiddenAreas(ranges);
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
let lineMappingChanged = this._lines.setHiddenAreas(ranges);
|
||||
if (lineMappingChanged) {
|
||||
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this.decorations.onLineMappingChanged();
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewFlushedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewLineMappingChangedEvent());
|
||||
eventsCollector.emitViewEvent(new viewEvents.ViewDecorationsChangedEvent(null));
|
||||
this._cursor.onLineMappingChanged(eventsCollector);
|
||||
this._decorations.onLineMappingChanged();
|
||||
this.viewLayout.onFlushed(this.getLineCount());
|
||||
this.viewLayout.onHeightMaybeChanged();
|
||||
}
|
||||
} finally {
|
||||
this._endEmit();
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
this._updateConfigurationViewLineCount.schedule();
|
||||
}
|
||||
|
||||
public getVisibleRangesPlusViewportAboveBelow(): Range[] {
|
||||
const layoutInfo = this.configuration.options.get(EditorOption.layoutInfo);
|
||||
const lineHeight = this.configuration.options.get(EditorOption.lineHeight);
|
||||
const layoutInfo = this._configuration.options.get(EditorOption.layoutInfo);
|
||||
const lineHeight = this._configuration.options.get(EditorOption.lineHeight);
|
||||
const linesAround = Math.max(20, Math.round(layoutInfo.height / lineHeight));
|
||||
const partialData = this.viewLayout.getLinesViewportData();
|
||||
const startViewLineNumber = Math.max(1, partialData.completelyVisibleStartLineNumber - linesAround);
|
||||
@@ -423,7 +456,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
|
||||
private _toModelVisibleRanges(visibleViewRange: Range): Range[] {
|
||||
const visibleRange = this.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);
|
||||
const hiddenAreas = this.lines.getHiddenAreas();
|
||||
const hiddenAreas = this._lines.getHiddenAreas();
|
||||
|
||||
if (hiddenAreas.length === 0) {
|
||||
return [visibleRange];
|
||||
@@ -528,48 +561,48 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
return this.model.getOptions().tabSize;
|
||||
}
|
||||
|
||||
public getOptions(): TextModelResolvedOptions {
|
||||
public getTextModelOptions(): TextModelResolvedOptions {
|
||||
return this.model.getOptions();
|
||||
}
|
||||
|
||||
public getLineCount(): number {
|
||||
return this.lines.getViewLineCount();
|
||||
return this._lines.getViewLineCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a hint that a lot of requests are about to come in for these line numbers.
|
||||
*/
|
||||
public setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void {
|
||||
this.viewportStartLine = startLineNumber;
|
||||
this._viewportStartLine = startLineNumber;
|
||||
let position = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(startLineNumber, this.getLineMinColumn(startLineNumber)));
|
||||
this.viewportStartLineTrackedRange = this.model._setTrackedRange(this.viewportStartLineTrackedRange, new Range(position.lineNumber, position.column, position.lineNumber, position.column), TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
||||
this._viewportStartLineTrackedRange = this.model._setTrackedRange(this._viewportStartLineTrackedRange, new Range(position.lineNumber, position.column, position.lineNumber, position.column), TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);
|
||||
const viewportStartLineTop = this.viewLayout.getVerticalOffsetForLineNumber(startLineNumber);
|
||||
const scrollTop = this.viewLayout.getCurrentScrollTop();
|
||||
this.viewportStartLineDelta = scrollTop - viewportStartLineTop;
|
||||
this._viewportStartLineDelta = scrollTop - viewportStartLineTop;
|
||||
}
|
||||
|
||||
public getActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo {
|
||||
return this.lines.getActiveIndentGuide(lineNumber, minLineNumber, maxLineNumber);
|
||||
return this._lines.getActiveIndentGuide(lineNumber, minLineNumber, maxLineNumber);
|
||||
}
|
||||
|
||||
public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] {
|
||||
return this.lines.getViewLinesIndentGuides(startLineNumber, endLineNumber);
|
||||
return this._lines.getViewLinesIndentGuides(startLineNumber, endLineNumber);
|
||||
}
|
||||
|
||||
public getLineContent(lineNumber: number): string {
|
||||
return this.lines.getViewLineContent(lineNumber);
|
||||
return this._lines.getViewLineContent(lineNumber);
|
||||
}
|
||||
|
||||
public getLineLength(lineNumber: number): number {
|
||||
return this.lines.getViewLineLength(lineNumber);
|
||||
return this._lines.getViewLineLength(lineNumber);
|
||||
}
|
||||
|
||||
public getLineMinColumn(lineNumber: number): number {
|
||||
return this.lines.getViewLineMinColumn(lineNumber);
|
||||
return this._lines.getViewLineMinColumn(lineNumber);
|
||||
}
|
||||
|
||||
public getLineMaxColumn(lineNumber: number): number {
|
||||
return this.lines.getViewLineMaxColumn(lineNumber);
|
||||
return this._lines.getViewLineMaxColumn(lineNumber);
|
||||
}
|
||||
|
||||
public getLineFirstNonWhitespaceColumn(lineNumber: number): number {
|
||||
@@ -589,15 +622,15 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
|
||||
public getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[] {
|
||||
return this.decorations.getDecorationsViewportData(visibleRange).decorations;
|
||||
return this._decorations.getDecorationsViewportData(visibleRange).decorations;
|
||||
}
|
||||
|
||||
public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
|
||||
let mightContainRTL = this.model.mightContainRTL();
|
||||
let mightContainNonBasicASCII = this.model.mightContainNonBasicASCII();
|
||||
let tabSize = this.getTabSize();
|
||||
let lineData = this.lines.getViewLineData(lineNumber);
|
||||
let allInlineDecorations = this.decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
|
||||
let lineData = this._lines.getViewLineData(lineNumber);
|
||||
let allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
|
||||
let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];
|
||||
|
||||
return new ViewLineRenderingData(
|
||||
@@ -615,11 +648,11 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
|
||||
public getViewLineData(lineNumber: number): ViewLineData {
|
||||
return this.lines.getViewLineData(lineNumber);
|
||||
return this._lines.getViewLineData(lineNumber);
|
||||
}
|
||||
|
||||
public getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData {
|
||||
let result = this.lines.getViewLinesData(startLineNumber, endLineNumber, needed);
|
||||
let result = this._lines.getViewLinesData(startLineNumber, endLineNumber, needed);
|
||||
return new MinimapLinesRenderingData(
|
||||
this.getTabSize(),
|
||||
result
|
||||
@@ -627,7 +660,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
|
||||
public getAllOverviewRulerDecorations(theme: EditorTheme): IOverviewRulerDecorations {
|
||||
return this.lines.getAllOverviewRulerDecorations(this.editorId, filterValidationDecorations(this.configuration.options), theme);
|
||||
return this._lines.getAllOverviewRulerDecorations(this._editorId, filterValidationDecorations(this._configuration.options), theme);
|
||||
}
|
||||
|
||||
public invalidateOverviewRulerColorCache(): void {
|
||||
@@ -769,7 +802,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
range = new Range(lineNumber, this.model.getLineMinColumn(lineNumber), lineNumber, this.model.getLineMaxColumn(lineNumber));
|
||||
}
|
||||
|
||||
const fontInfo = this.configuration.options.get(EditorOption.fontInfo);
|
||||
const fontInfo = this._configuration.options.get(EditorOption.fontInfo);
|
||||
const colorMap = this._getColorMap();
|
||||
const fontFamily = fontInfo.fontFamily === EDITOR_FONT_DEFAULTS.fontFamily ? fontInfo.fontFamily : `'${fontInfo.fontFamily}', ${EDITOR_FONT_DEFAULTS.fontFamily}`;
|
||||
|
||||
@@ -827,4 +860,150 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//#region model
|
||||
|
||||
public pushStackElement(): void {
|
||||
this.model.pushStackElement();
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region cursor operations
|
||||
|
||||
public getPrimaryCursorState(): CursorState {
|
||||
return this._cursor.getPrimaryCursorState();
|
||||
}
|
||||
public getLastAddedCursorIndex(): number {
|
||||
return this._cursor.getLastAddedCursorIndex();
|
||||
}
|
||||
public getCursorStates(): CursorState[] {
|
||||
return this._cursor.getCursorStates();
|
||||
}
|
||||
public setCursorStates(source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.setStates(eventsCollector, source, reason, states));
|
||||
}
|
||||
public getCursorColumnSelectData(): IColumnSelectData {
|
||||
return this._cursor.getCursorColumnSelectData();
|
||||
}
|
||||
public setCursorColumnSelectData(columnSelectData: IColumnSelectData): void {
|
||||
this._cursor.setCursorColumnSelectData(columnSelectData);
|
||||
}
|
||||
public getPrevEditOperationType(): EditOperationType {
|
||||
return this._cursor.getPrevEditOperationType();
|
||||
}
|
||||
public setPrevEditOperationType(type: EditOperationType): void {
|
||||
this._cursor.setPrevEditOperationType(type);
|
||||
}
|
||||
public getSelection(): Selection {
|
||||
return this._cursor.getSelection();
|
||||
}
|
||||
public getSelections(): Selection[] {
|
||||
return this._cursor.getSelections();
|
||||
}
|
||||
public getPosition(): Position {
|
||||
return this._cursor.getPrimaryCursorState().modelState.position;
|
||||
}
|
||||
public setSelections(source: string | null | undefined, selections: readonly ISelection[]): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.setSelections(eventsCollector, source, selections));
|
||||
}
|
||||
public saveCursorState(): ICursorState[] {
|
||||
return this._cursor.saveState();
|
||||
}
|
||||
public restoreCursorState(states: ICursorState[]): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.restoreState(eventsCollector, states));
|
||||
}
|
||||
|
||||
private _executeCursorEdit(callback: (eventsCollector: ViewModelEventsCollector) => void): void {
|
||||
if (this._cursor.context.cursorConfig.readOnly) {
|
||||
// we cannot edit when read only...
|
||||
this._eventDispatcher.emitOutgoingEvent(new ReadOnlyEditAttemptEvent());
|
||||
return;
|
||||
}
|
||||
this._withViewEventsCollector(callback);
|
||||
}
|
||||
public executeEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.executeEdits(eventsCollector, source, edits, cursorStateComputer));
|
||||
}
|
||||
public startComposition(): void {
|
||||
this._cursor.setIsDoingComposition(true);
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.startComposition(eventsCollector));
|
||||
}
|
||||
public endComposition(source?: string | null | undefined): void {
|
||||
this._cursor.setIsDoingComposition(false);
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.endComposition(eventsCollector, source));
|
||||
}
|
||||
public type(text: string, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.type(eventsCollector, text, source));
|
||||
}
|
||||
public replacePreviousChar(text: string, replaceCharCnt: number, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.replacePreviousChar(eventsCollector, text, replaceCharCnt, source));
|
||||
}
|
||||
public paste(text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.paste(eventsCollector, text, pasteOnNewLine, multicursorText, source));
|
||||
}
|
||||
public cut(source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.cut(eventsCollector, source));
|
||||
}
|
||||
public executeCommand(command: ICommand, source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.executeCommand(eventsCollector, command, source));
|
||||
}
|
||||
public executeCommands(commands: ICommand[], source?: string | null | undefined): void {
|
||||
this._executeCursorEdit(eventsCollector => this._cursor.executeCommands(eventsCollector, commands, source));
|
||||
}
|
||||
public revealPrimaryCursor(source: string | null | undefined, revealHorizontal: boolean): void {
|
||||
this._withViewEventsCollector(eventsCollector => this._cursor.revealPrimary(eventsCollector, source, revealHorizontal, ScrollType.Smooth));
|
||||
}
|
||||
public revealTopMostCursor(source: string | null | undefined): void {
|
||||
const viewPosition = this._cursor.getTopMostViewPosition();
|
||||
const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
|
||||
this._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, viewEvents.VerticalRevealType.Simple, true, ScrollType.Smooth)));
|
||||
}
|
||||
public revealBottomMostCursor(source: string | null | undefined): void {
|
||||
const viewPosition = this._cursor.getBottomMostViewPosition();
|
||||
const viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
|
||||
this._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, viewEvents.VerticalRevealType.Simple, true, ScrollType.Smooth)));
|
||||
}
|
||||
public revealRange(source: string | null | undefined, revealHorizontal: boolean, viewRange: Range, verticalType: viewEvents.VerticalRevealType, scrollType: ScrollType): void {
|
||||
this._withViewEventsCollector(eventsCollector => eventsCollector.emitViewEvent(new viewEvents.ViewRevealRangeRequestEvent(source, viewRange, null, verticalType, revealHorizontal, scrollType)));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region viewLayout
|
||||
public getVerticalOffsetForLineNumber(viewLineNumber: number): number {
|
||||
return this.viewLayout.getVerticalOffsetForLineNumber(viewLineNumber);
|
||||
}
|
||||
public getScrollTop(): number {
|
||||
return this.viewLayout.getCurrentScrollTop();
|
||||
}
|
||||
public setScrollTop(newScrollTop: number, scrollType: ScrollType): void {
|
||||
this.viewLayout.setScrollPosition({ scrollTop: newScrollTop }, scrollType);
|
||||
}
|
||||
public setScrollPosition(position: INewScrollPosition, type: ScrollType): void {
|
||||
this.viewLayout.setScrollPosition(position, type);
|
||||
}
|
||||
public deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void {
|
||||
this.viewLayout.deltaScrollNow(deltaScrollLeft, deltaScrollTop);
|
||||
}
|
||||
public changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): void {
|
||||
const hadAChange = this.viewLayout.changeWhitespace(callback);
|
||||
if (hadAChange) {
|
||||
this._eventDispatcher.emitSingleViewEvent(new viewEvents.ViewZonesChangedEvent());
|
||||
this._eventDispatcher.emitOutgoingEvent(new ViewZonesChangedEvent());
|
||||
}
|
||||
}
|
||||
public setMaxLineWidth(maxLineWidth: number): void {
|
||||
this.viewLayout.setMaxLineWidth(maxLineWidth);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
private _withViewEventsCollector(callback: (eventsCollector: ViewModelEventsCollector) => void): void {
|
||||
try {
|
||||
const eventsCollector = this._eventDispatcher.beginEmitViewEvents();
|
||||
callback(eventsCollector);
|
||||
} finally {
|
||||
this._eventDispatcher.endEmitViewEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user