mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-07 15:26:49 +01:00
fixes #177
This commit is contained in:
@@ -1452,6 +1452,18 @@ export interface ITokenizedModel extends ITextModel {
|
||||
* @param position The position at which to look for a bracket.
|
||||
*/
|
||||
matchBracket(position:IPosition, inaccurateResultAcceptable?:boolean): IMatchBracketResult;
|
||||
|
||||
/**
|
||||
* No mode supports allowed on this model because it is simply too large.
|
||||
* (even tokenization would cause too much memory pressure)
|
||||
*/
|
||||
isTooLargeForHavingAMode(): boolean;
|
||||
|
||||
/**
|
||||
* Only basic mode supports allowed on this model because it is simply too large.
|
||||
* (tokenization is allowed and other basic supports)
|
||||
*/
|
||||
isTooLargeForHavingARichMode(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,11 @@ import {IResourceService} from 'vs/editor/common/services/resourceService';
|
||||
import {URL} from 'vs/base/common/network';
|
||||
import {disposeAll} from 'vs/base/common/lifecycle';
|
||||
|
||||
export interface IMirrorModelEvents {
|
||||
contentChanged: EditorCommon.IModelContentChangedEvent[];
|
||||
propertiesChanged: EditorCommon.IModelPropertiesChangedEvent;
|
||||
}
|
||||
|
||||
export class AbstractMirrorModel extends TextModelWithTokens implements EditorCommon.IMirrorModel {
|
||||
|
||||
_lineStarts:PrefixSumComputer;
|
||||
@@ -453,51 +458,43 @@ export class MirrorModel extends AbstractMirrorModel implements EditorCommon.IMi
|
||||
return false;
|
||||
}
|
||||
|
||||
public onEvents(events:{ type:string; }[]) : boolean {
|
||||
public onEvents(events:IMirrorModelEvents) : boolean {
|
||||
if (this._isDisposed) {
|
||||
throw new Error('MirrorModel.onEvents: Model is disposed');
|
||||
}
|
||||
|
||||
var changed = false;
|
||||
for (var i = 0, len = events.length; i < len; i++) {
|
||||
var e = events[i];
|
||||
switch (e.type) {
|
||||
case EditorCommon.EventType.ModelContentChanged:
|
||||
var contentChangedEvent = <EditorCommon.IModelContentChangedEvent><any>e;
|
||||
if (events.propertiesChanged) {
|
||||
this._extraProperties = events.propertiesChanged.properties;
|
||||
}
|
||||
|
||||
// Force recreating of line starts
|
||||
this._lineStarts = null;
|
||||
let changed = false;
|
||||
for (let i = 0, len = events.contentChanged.length; i < len; i++) {
|
||||
let contentChangedEvent = events.contentChanged[i];
|
||||
|
||||
this._setVersionId(contentChangedEvent.versionId);
|
||||
switch (contentChangedEvent.changeType) {
|
||||
case EditorCommon.EventType.ModelContentChangedFlush:
|
||||
this._onLinesFlushed(<EditorCommon.IModelContentChangedFlushEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
// Force recreating of line starts
|
||||
this._lineStarts = null;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLinesDeleted:
|
||||
this._onLinesDeleted(<EditorCommon.IModelContentChangedLinesDeletedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLinesInserted:
|
||||
this._onLinesInserted(<EditorCommon.IModelContentChangedLinesInsertedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLineChanged:
|
||||
this._onLineChanged(<EditorCommon.IModelContentChangedLineChangedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
this._setVersionId(contentChangedEvent.versionId);
|
||||
switch (contentChangedEvent.changeType) {
|
||||
case EditorCommon.EventType.ModelContentChangedFlush:
|
||||
this._onLinesFlushed(<EditorCommon.IModelContentChangedFlushEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelPropertiesChanged:
|
||||
this._extraProperties = (<any>e).properties;
|
||||
case EditorCommon.EventType.ModelContentChangedLinesDeleted:
|
||||
this._onLinesDeleted(<EditorCommon.IModelContentChangedLinesDeletedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn('Unknown model event: ' + e.type);
|
||||
case EditorCommon.EventType.ModelContentChangedLinesInserted:
|
||||
this._onLinesInserted(<EditorCommon.IModelContentChangedLinesInsertedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLineChanged:
|
||||
this._onLineChanged(<EditorCommon.IModelContentChangedLineChangedEvent>contentChangedEvent);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
|
||||
|
||||
private static MODE_TOKENIZATION_FAILED_MSG = nls.localize('mode.tokenizationSupportFailed', "The mode has failed while tokenizing the input.");
|
||||
private static MODEL_SYNC_LIMIT = 5 * 1024 * 1024; // 5 MB
|
||||
private static MODEL_TOKENIZATION_LIMIT = 50 * 1024 * 1024; // 50 MB
|
||||
private static MODEL_TOKENIZATION_LIMIT = 20 * 1024 * 1024; // 20 MB
|
||||
|
||||
private _shouldAutoTokenize:boolean;
|
||||
private _mode: Modes.IMode;
|
||||
@@ -262,12 +262,20 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public isTooLargeForHavingAMode(): boolean {
|
||||
return this._shouldDenyMode;
|
||||
}
|
||||
|
||||
public isTooLargeForHavingARichMode(): boolean {
|
||||
return this._shouldSimplifyMode;
|
||||
}
|
||||
|
||||
private _massageMode(mode: Modes.IMode): Modes.IMode {
|
||||
if (this._shouldDenyMode) {
|
||||
if (this.isTooLargeForHavingAMode()) {
|
||||
return new NullMode();
|
||||
}
|
||||
if (this._shouldSimplifyMode) {
|
||||
return new SimplifiedMode(mode);
|
||||
if (this.isTooLargeForHavingARichMode()) {
|
||||
return mode.toSimplifiedMode();
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
@@ -856,27 +864,3 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
|
||||
return BracketsHelper.matchBracket(this, this.validatePosition(position), inaccurateResultAcceptable);
|
||||
}
|
||||
}
|
||||
|
||||
class SimplifiedMode implements Modes.IMode {
|
||||
|
||||
tokenizationSupport: Modes.ITokenizationSupport;
|
||||
electricCharacterSupport: Modes.IElectricCharacterSupport;
|
||||
commentsSupport: Modes.ICommentsSupport;
|
||||
characterPairSupport: Modes.ICharacterPairSupport;
|
||||
tokenTypeClassificationSupport: Modes.ITokenTypeClassificationSupport;
|
||||
|
||||
private _id: string;
|
||||
|
||||
constructor(sourceMode: Modes.IMode) {
|
||||
this._id = 'vs.editor.modes.simplifiedMode:' + sourceMode.getId();
|
||||
this.tokenizationSupport = sourceMode.tokenizationSupport;
|
||||
this.electricCharacterSupport = sourceMode.electricCharacterSupport;
|
||||
this.commentsSupport = sourceMode.commentsSupport;
|
||||
this.characterPairSupport = sourceMode.characterPairSupport;
|
||||
this.tokenTypeClassificationSupport = sourceMode.tokenTypeClassificationSupport;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,11 @@ export interface IMode {
|
||||
|
||||
getId(): string;
|
||||
|
||||
/**
|
||||
* Return a mode "similar" to this one that strips any "smart" supports.
|
||||
*/
|
||||
toSimplifiedMode(): IMode;
|
||||
|
||||
addSupportChangedListener?(callback: (e: EditorCommon.IModeSupportChangedEvent) => void): IDisposable;
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,7 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
|
||||
// adapters end
|
||||
|
||||
private _eventEmitter = new EventEmitter();
|
||||
private _simplifiedMode: Modes.IMode;
|
||||
|
||||
constructor(
|
||||
descriptor:Modes.IModeDescriptor,
|
||||
@@ -73,6 +74,7 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
|
||||
this.tokenTypeClassificationSupport = this;
|
||||
|
||||
this._workerPiecePromise = null;
|
||||
this._simplifiedMode = null;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
@@ -86,6 +88,13 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
|
||||
}
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): Modes.IMode {
|
||||
if (!this._simplifiedMode) {
|
||||
this._simplifiedMode = new SimplifiedMode(this);
|
||||
}
|
||||
return this._simplifiedMode;
|
||||
}
|
||||
|
||||
private _getOrCreateWorker(): TPromise<W> {
|
||||
if (!this._workerPiecePromise) {
|
||||
var workerDescriptor: AsyncDescriptor2<Modes.IMode, Modes.IWorkerParticipant[], W> = this._getWorkerDescriptor();
|
||||
@@ -236,7 +245,84 @@ export class AbstractMode<W extends AbstractModeWorker> implements Modes.IMode {
|
||||
}
|
||||
}
|
||||
|
||||
class SimplifiedMode implements Modes.IMode {
|
||||
|
||||
tokenizationSupport: Modes.ITokenizationSupport;
|
||||
electricCharacterSupport: Modes.IElectricCharacterSupport;
|
||||
commentsSupport: Modes.ICommentsSupport;
|
||||
characterPairSupport: Modes.ICharacterPairSupport;
|
||||
tokenTypeClassificationSupport: Modes.ITokenTypeClassificationSupport;
|
||||
onEnterSupport: Modes.IOnEnterSupport;
|
||||
|
||||
private _sourceMode: Modes.IMode;
|
||||
private _eventEmitter: EventEmitter;
|
||||
private _id: string;
|
||||
|
||||
constructor(sourceMode: Modes.IMode) {
|
||||
this._sourceMode = sourceMode;
|
||||
this._eventEmitter = new EventEmitter();
|
||||
this._id = 'vs.editor.modes.simplifiedMode:' + sourceMode.getId();
|
||||
this._assignSupports();
|
||||
|
||||
if (this._sourceMode.addSupportChangedListener) {
|
||||
this._sourceMode.addSupportChangedListener((e) => {
|
||||
if (e.tokenizationSupport || e.electricCharacterSupport || e.commentsSupport || e.characterPairSupport || e.tokenTypeClassificationSupport || e.onEnterSupport) {
|
||||
this._assignSupports();
|
||||
let newEvent = SimplifiedMode._createModeSupportChangedEvent(e);
|
||||
this._eventEmitter.emit('modeSupportChanged', newEvent);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): Modes.IMode {
|
||||
return this;
|
||||
}
|
||||
|
||||
private _assignSupports(): void {
|
||||
this.tokenizationSupport = this._sourceMode.tokenizationSupport;
|
||||
this.electricCharacterSupport = this._sourceMode.electricCharacterSupport;
|
||||
this.commentsSupport = this._sourceMode.commentsSupport;
|
||||
this.characterPairSupport = this._sourceMode.characterPairSupport;
|
||||
this.tokenTypeClassificationSupport = this._sourceMode.tokenTypeClassificationSupport;
|
||||
this.onEnterSupport = this._sourceMode.onEnterSupport;
|
||||
}
|
||||
|
||||
private static _createModeSupportChangedEvent(originalModeEvent:EditorCommon.IModeSupportChangedEvent): EditorCommon.IModeSupportChangedEvent {
|
||||
var event = {
|
||||
codeLensSupport: false,
|
||||
tokenizationSupport: originalModeEvent.tokenizationSupport,
|
||||
occurrencesSupport:false,
|
||||
declarationSupport:false,
|
||||
typeDeclarationSupport:false,
|
||||
navigateTypesSupport:false,
|
||||
referenceSupport:false,
|
||||
suggestSupport:false,
|
||||
parameterHintsSupport:false,
|
||||
extraInfoSupport:false,
|
||||
outlineSupport:false,
|
||||
logicalSelectionSupport:false,
|
||||
formattingSupport:false,
|
||||
inplaceReplaceSupport:false,
|
||||
diffSupport:false,
|
||||
dirtyDiffSupport:false,
|
||||
emitOutputSupport:false,
|
||||
linkSupport:false,
|
||||
configSupport:false,
|
||||
electricCharacterSupport: originalModeEvent.electricCharacterSupport,
|
||||
commentsSupport: originalModeEvent.commentsSupport,
|
||||
characterPairSupport: originalModeEvent.characterPairSupport,
|
||||
tokenTypeClassificationSupport: originalModeEvent.tokenTypeClassificationSupport,
|
||||
quickFixSupport:false,
|
||||
onEnterSupport: originalModeEvent.onEnterSupport
|
||||
};
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
export var isDigit:(character:string, base:number)=>boolean = (function () {
|
||||
|
||||
|
||||
@@ -91,6 +91,10 @@ export class NullMode implements Modes.IMode {
|
||||
return NullMode.ID;
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): Modes.IMode {
|
||||
return this;
|
||||
}
|
||||
|
||||
public getWordDefinition():RegExp {
|
||||
return NullMode.DEFAULT_WORD_REGEXP;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ export interface IModelService {
|
||||
|
||||
destroyModel(resource: URL): void;
|
||||
|
||||
removeModel(model: EditorCommon.IModel): void;
|
||||
|
||||
getModels(): EditorCommon.IModel[];
|
||||
|
||||
getModel(resource: URI): EditorCommon.IModel;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import {IEmitterEvent} from 'vs/base/common/eventEmitter';
|
||||
import {IModeService} from 'vs/editor/common/services/modeService';
|
||||
import {IMarker, IMarkerService} from 'vs/platform/markers/common/markers';
|
||||
import {MirrorModel} from 'vs/editor/common/model/mirrorModel';
|
||||
import {IMirrorModelEvents, MirrorModel} from 'vs/editor/common/model/mirrorModel';
|
||||
import {Range} from 'vs/editor/common/core/range';
|
||||
import EditorCommon = require('vs/editor/common/editorCommon');
|
||||
import Modes = require('vs/editor/common/modes');
|
||||
@@ -21,7 +21,7 @@ import URI from 'vs/base/common/uri';
|
||||
import {URL} from 'vs/base/common/network';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import {EventProvider} from 'vs/base/common/eventProvider';
|
||||
import {IDisposable} from 'vs/base/common/lifecycle';
|
||||
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
|
||||
import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import Errors = require('vs/base/common/errors');
|
||||
import {anonymize} from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -35,53 +35,69 @@ export interface IRawModelData {
|
||||
modeId:string;
|
||||
}
|
||||
|
||||
class BoundModel implements IDisposable {
|
||||
function MODEL_ID(resource:URI): string {
|
||||
return resource.toString();
|
||||
}
|
||||
|
||||
model:EditorCommon.IModel;
|
||||
toUnbind:Function;
|
||||
private _decorationIds: string[];
|
||||
class ModelData implements IDisposable {
|
||||
model: EditorCommon.IModel;
|
||||
isSyncedToWorkers: boolean;
|
||||
|
||||
constructor(model:EditorCommon.IModel) {
|
||||
private _markerDecorations: string[];
|
||||
private _modelEventsListener: IDisposable;
|
||||
|
||||
constructor(model: EditorCommon.IModel, eventsHandler:(modelData:ModelData, events:IEmitterEvent[])=>void) {
|
||||
this.model = model;
|
||||
this.toUnbind = null;
|
||||
this.isSyncedToWorkers = false;
|
||||
|
||||
this._markerDecorations = [];
|
||||
this._modelEventsListener = model.addBulkListener2((events) => eventsHandler(this, events));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
this._decorationIds = this.model.deltaDecorations(this._decorationIds, []);
|
||||
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
|
||||
this._modelEventsListener.dispose();
|
||||
this._modelEventsListener = null;
|
||||
this.model = null;
|
||||
|
||||
if (this.toUnbind) {
|
||||
this.toUnbind();
|
||||
this.toUnbind = null;
|
||||
}
|
||||
}
|
||||
|
||||
public deltaMarkers(markers:IMarker[]):void {
|
||||
public getModelId(): string {
|
||||
return MODEL_ID(this.model.getAssociatedResource());
|
||||
}
|
||||
|
||||
public acceptMarkerDecorations(newDecorations:EditorCommon.IModelDeltaDecoration[]): void {
|
||||
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations);
|
||||
}
|
||||
}
|
||||
|
||||
class ModelMarkerHandler {
|
||||
|
||||
public static setMarkers(modelData:ModelData, markers:IMarker[]):void {
|
||||
|
||||
// Limit to the first 500 errors/warnings
|
||||
markers = markers.slice(0, 500);
|
||||
|
||||
var newModelDecorations = markers.map(marker => {
|
||||
return <EditorCommon.IModelDeltaDecoration> {
|
||||
range: this._createDecorationRange(marker),
|
||||
let newModelDecorations:EditorCommon.IModelDeltaDecoration[] = markers.map((marker) => {
|
||||
return {
|
||||
range: this._createDecorationRange(modelData.model, marker),
|
||||
options: this._createDecorationOption(marker)
|
||||
};
|
||||
});
|
||||
this._decorationIds = this.model.deltaDecorations(this._decorationIds, newModelDecorations);
|
||||
|
||||
modelData.acceptMarkerDecorations(newModelDecorations);
|
||||
}
|
||||
|
||||
private _createDecorationRange(rawMarker: IMarker): EditorCommon.IRange {
|
||||
var marker = this.model.validateRange(new Range(rawMarker.startLineNumber, rawMarker.startColumn, rawMarker.endLineNumber, rawMarker.endColumn));
|
||||
var ret: EditorCommon.IEditorRange = new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn);
|
||||
private static _createDecorationRange(model:EditorCommon.IModel, rawMarker: IMarker): EditorCommon.IRange {
|
||||
let marker = model.validateRange(new Range(rawMarker.startLineNumber, rawMarker.startColumn, rawMarker.endLineNumber, rawMarker.endColumn));
|
||||
let ret: EditorCommon.IEditorRange = new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn);
|
||||
if (ret.isEmpty()) {
|
||||
var word = this.model.getWordAtPosition(ret.getStartPosition());
|
||||
let word = model.getWordAtPosition(ret.getStartPosition());
|
||||
if (word) {
|
||||
ret.startColumn = word.startColumn;
|
||||
ret.endColumn = word.endColumn;
|
||||
} else {
|
||||
var maxColumn = this.model.getLineLastNonWhitespaceColumn(marker.startLineNumber) ||
|
||||
this.model.getLineMaxColumn(marker.startLineNumber);
|
||||
let maxColumn = model.getLineLastNonWhitespaceColumn(marker.startLineNumber) ||
|
||||
model.getLineMaxColumn(marker.startLineNumber);
|
||||
|
||||
if (maxColumn === 1) {
|
||||
// empty line
|
||||
@@ -96,7 +112,7 @@ class BoundModel implements IDisposable {
|
||||
}
|
||||
}
|
||||
} else if (rawMarker.endColumn === Number.MAX_VALUE && rawMarker.startColumn === 1 && ret.startLineNumber === ret.endLineNumber) {
|
||||
var minColumn = this.model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
|
||||
let minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
|
||||
if (minColumn < ret.endColumn) {
|
||||
ret.startColumn = minColumn;
|
||||
rawMarker.startColumn = minColumn;
|
||||
@@ -105,7 +121,7 @@ class BoundModel implements IDisposable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private _createDecorationOption(marker:IMarker): EditorCommon.IModelDecorationOptions {
|
||||
private static _createDecorationOption(marker:IMarker): EditorCommon.IModelDecorationOptions {
|
||||
|
||||
let className: string;
|
||||
let color: string;
|
||||
@@ -151,14 +167,9 @@ class BoundModel implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
export interface IModelsEvents {
|
||||
[url:string]: any[];
|
||||
}
|
||||
|
||||
export class ModelServiceImpl implements IModelService {
|
||||
public serviceId = IModelService;
|
||||
|
||||
private _models: {[modelId:string]:BoundModel;};
|
||||
private _markerService: IMarkerService;
|
||||
private _markerServiceSubscription: IDisposable;
|
||||
private _threadService: IThreadService;
|
||||
@@ -167,9 +178,11 @@ export class ModelServiceImpl implements IModelService {
|
||||
private _onModelAdded: EventSource<(model: EditorCommon.IModel) => void>;
|
||||
private _onModelRemoved: EventSource<(model: EditorCommon.IModel) => void>;
|
||||
private _onModelModeChanged: EventSource<(model: EditorCommon.IModel, oldModeId:string) => void>;
|
||||
private _accumulatedModelEvents: IModelsEvents;
|
||||
private _lastSentModelEventsTime: number;
|
||||
private _sendModelEventsTimerId: number;
|
||||
|
||||
/**
|
||||
* All the models known in the system.
|
||||
*/
|
||||
private _models: {[modelId:string]:ModelData;};
|
||||
|
||||
constructor(threadService: IThreadService, markerService: IMarkerService) {
|
||||
this._threadService = threadService;
|
||||
@@ -185,137 +198,75 @@ export class ModelServiceImpl implements IModelService {
|
||||
if(this._markerService) {
|
||||
this._markerServiceSubscription = this._markerService.onMarkerChanged(this._handleMarkerChange, this);
|
||||
}
|
||||
|
||||
this._accumulatedModelEvents = {};
|
||||
this._lastSentModelEventsTime = -1;
|
||||
this._sendModelEventsTimerId = -1;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if(this._markerServiceSubscription) {
|
||||
this._markerServiceSubscription.dispose();
|
||||
}
|
||||
if (this._sendModelEventsTimerId !== -1) {
|
||||
clearTimeout(this._sendModelEventsTimerId);
|
||||
this._sendModelEventsTimerId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private _sendModelEvents(url:URL, events:any[]): void {
|
||||
let modelId = url.toString();
|
||||
this._accumulatedModelEvents[modelId] = this._accumulatedModelEvents[modelId] || [];
|
||||
this._accumulatedModelEvents[modelId] = this._accumulatedModelEvents[modelId].concat(events);
|
||||
|
||||
this._sendModelEventsNow();
|
||||
// this._scheduleSendModelEvents();
|
||||
}
|
||||
|
||||
// private _scheduleSendModelEvents(): void {
|
||||
// if (this._sendModelEventsTimerId !== -1) {
|
||||
// // sending model events already scheduled
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let elapsed = Date.now() - this._lastSentModelEventsTime;
|
||||
// if (elapsed >= 100) {
|
||||
// // more than 100ms have passed since last model events have been sent => send events now
|
||||
// this._sendModelEventsNow();
|
||||
// } else {
|
||||
// this._sendModelEventsTimerId = setTimeout(() => {
|
||||
// this._sendModelEventsTimerId = -1;
|
||||
// this._sendModelEventsNow();
|
||||
// }, 100 - elapsed);
|
||||
// }
|
||||
// }
|
||||
|
||||
private _sendModelEventsNow(): void {
|
||||
this._lastSentModelEventsTime = Date.now();
|
||||
|
||||
let sendingEvents = this._accumulatedModelEvents;
|
||||
this._accumulatedModelEvents = {};
|
||||
this._workerHelper.$onModelsEvents(sendingEvents);
|
||||
}
|
||||
|
||||
private _handleMarkerChange(changedResources: URI[]): void {
|
||||
|
||||
changedResources.forEach(resource => {
|
||||
var boundModel = this._models[resource.toString()];
|
||||
if (!boundModel) {
|
||||
changedResources.forEach((resource) => {
|
||||
let modelId = MODEL_ID(resource);
|
||||
let modelData = this._models[modelId];
|
||||
if (!modelData) {
|
||||
return;
|
||||
}
|
||||
boundModel.deltaMarkers(this._markerService.read({ resource: resource, take: 500 }));
|
||||
ModelMarkerHandler.setMarkers(modelData, this._markerService.read({ resource: resource, take: 500 }));
|
||||
});
|
||||
}
|
||||
|
||||
// --- begin IModelService
|
||||
|
||||
public createModel(value:string, modeOrPromise:TPromise<Modes.IMode>|Modes.IMode, resource: URL): EditorCommon.IModel {
|
||||
var model = new Model(value, modeOrPromise, resource);
|
||||
this.addModel(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
public addModel(model:EditorCommon.IModel): void {
|
||||
var modelId = model.getAssociatedResource().toString();
|
||||
private _createModelData(value:string, modeOrPromise:TPromise<Modes.IMode>|Modes.IMode, resource: URL): ModelData {
|
||||
// create & save the model
|
||||
let model = new Model(value, modeOrPromise, resource);
|
||||
let modelId = MODEL_ID(model.getAssociatedResource());
|
||||
|
||||
if (this._models[modelId]) {
|
||||
// There already exists a model with this id => this is a programmer error
|
||||
throw new Error('BoundModels: Cannot add model ' + anonymize(modelId) + ' because it already exists!');
|
||||
throw new Error('ModelService: Cannot add model ' + anonymize(modelId) + ' because it already exists!');
|
||||
}
|
||||
|
||||
var boundModel = new BoundModel(model);
|
||||
let modelData = new ModelData(model, (modelData, events) => this._onModelEvents(modelData, events));
|
||||
this._models[modelId] = modelData;
|
||||
|
||||
boundModel.toUnbind = model.addBulkListener((events) => this._onModelEvents(modelId, events));
|
||||
if(this._markerService) {
|
||||
boundModel.deltaMarkers(this._markerService.read({ resource: model.getAssociatedResource() }));
|
||||
}
|
||||
this._models[modelId] = boundModel;
|
||||
|
||||
// Create model in workers
|
||||
this._workerHelper.$createModel(ModelServiceImpl._getBoundModelData(model));
|
||||
this._onModelAdded.fire(model);
|
||||
return modelData;
|
||||
}
|
||||
|
||||
public removeModel(model:EditorCommon.IModel): void {
|
||||
var modelId = model.getAssociatedResource().toString();
|
||||
|
||||
if (this._accumulatedModelEvents[modelId]) {
|
||||
delete this._accumulatedModelEvents[modelId];
|
||||
}
|
||||
|
||||
if (!this._models[modelId]) {
|
||||
// There is no model with this id => this is a programmer error
|
||||
throw new Error('BoundModels: Cannot remove model ' + anonymize(modelId) + ' because it doesn\'t exist!');
|
||||
}
|
||||
|
||||
// Dispose model in workers
|
||||
this._workerHelper.$disposeModel(model.getAssociatedResource());
|
||||
// this._modelDispose(model.getAssociatedResource());
|
||||
this._models[modelId].dispose();
|
||||
|
||||
delete this._models[modelId];
|
||||
public createModel(value:string, modeOrPromise:TPromise<Modes.IMode>|Modes.IMode, resource: URL): EditorCommon.IModel {
|
||||
let modelData = this._createModelData(value, modeOrPromise, resource);
|
||||
let modelId = modelData.getModelId();
|
||||
|
||||
// handle markers (marker service => model)
|
||||
if (this._markerService) {
|
||||
var markers = this._markerService.read({ resource: model.getAssociatedResource() }),
|
||||
owners: { [o: string]: any } = Object.create(null);
|
||||
|
||||
markers.forEach(marker => owners[marker.owner] = this);
|
||||
Object.keys(owners).forEach(owner => this._markerService.changeOne(owner, model.getAssociatedResource(), []));
|
||||
ModelMarkerHandler.setMarkers(modelData, this._markerService.read({ resource: modelData.model.getAssociatedResource() }));
|
||||
}
|
||||
|
||||
this._onModelRemoved.fire(model);
|
||||
if (!modelData.model.isTooLargeForHavingARichMode()) {
|
||||
// send this model to the workers
|
||||
modelData.isSyncedToWorkers = true;
|
||||
this._workerHelper.$_acceptNewModel(ModelServiceImpl._getBoundModelData(modelData.model));
|
||||
}
|
||||
|
||||
this._onModelAdded.fire(modelData.model);
|
||||
|
||||
return modelData.model;
|
||||
}
|
||||
|
||||
public destroyModel(resource: URL): void {
|
||||
let model = this.getModel(resource);
|
||||
if (model) {
|
||||
model.destroy();
|
||||
// We need to support that not all models get disposed through this service (i.e. model.dispose() should work!)
|
||||
let modelData = this._models[MODEL_ID(resource)];
|
||||
if (!modelData) {
|
||||
return;
|
||||
}
|
||||
modelData.model.dispose();
|
||||
}
|
||||
|
||||
public getModels(): EditorCommon.IModel[] {
|
||||
var ret: EditorCommon.IModel[] = [];
|
||||
for (var modelId in this._models) {
|
||||
let ret: EditorCommon.IModel[] = [];
|
||||
for (let modelId in this._models) {
|
||||
if (this._models.hasOwnProperty(modelId)) {
|
||||
ret.push(this._models[modelId].model);
|
||||
}
|
||||
@@ -324,11 +275,12 @@ export class ModelServiceImpl implements IModelService {
|
||||
}
|
||||
|
||||
public getModel(resource: URL): EditorCommon.IModel {
|
||||
var boundModel = this._models[resource.toString()];
|
||||
if (boundModel) {
|
||||
return boundModel.model;
|
||||
let modelId = MODEL_ID(resource);
|
||||
let modelData = this._models[modelId];
|
||||
if (!modelData) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return modelData.model;
|
||||
}
|
||||
|
||||
public get onModelAdded(): EventProvider<(model:EditorCommon.IModel)=>void> {
|
||||
@@ -345,6 +297,30 @@ export class ModelServiceImpl implements IModelService {
|
||||
|
||||
// --- end IModelService
|
||||
|
||||
private _onModelDisposing(model:EditorCommon.IModel): void {
|
||||
let modelId = MODEL_ID(model.getAssociatedResource());
|
||||
let modelData = this._models[modelId];
|
||||
|
||||
// TODO@Joh why are we removing markers here?
|
||||
if (this._markerService) {
|
||||
var markers = this._markerService.read({ resource: model.getAssociatedResource() }),
|
||||
owners: { [o: string]: any } = Object.create(null);
|
||||
|
||||
markers.forEach(marker => owners[marker.owner] = this);
|
||||
Object.keys(owners).forEach(owner => this._markerService.changeOne(owner, model.getAssociatedResource(), []));
|
||||
}
|
||||
|
||||
if (modelData.isSyncedToWorkers) {
|
||||
// Dispose model in workers
|
||||
this._workerHelper.$_acceptDidDisposeModel(model.getAssociatedResource());
|
||||
}
|
||||
|
||||
delete this._models[modelId];
|
||||
modelData.dispose();
|
||||
|
||||
this._onModelRemoved.fire(model);
|
||||
}
|
||||
|
||||
private static _getBoundModelData(model:EditorCommon.IModel): IRawModelData {
|
||||
return {
|
||||
url: model.getAssociatedResource(),
|
||||
@@ -355,67 +331,47 @@ export class ModelServiceImpl implements IModelService {
|
||||
};
|
||||
}
|
||||
|
||||
private _onModelEvents(modelId:string, events:IEmitterEvent[]): void {
|
||||
private _onModelEvents(modelData:ModelData, events:IEmitterEvent[]): void {
|
||||
let eventsForWorkers: IMirrorModelEvents = { contentChanged: [], propertiesChanged: null };
|
||||
|
||||
var resultingEvents:any[] = [],
|
||||
changed = false,
|
||||
i:number,
|
||||
len:number;
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
let e = events[i];
|
||||
let data = e.getData();
|
||||
|
||||
for (i = 0, len = events.length; i < len; i++) {
|
||||
var e = events[i];
|
||||
var data = e.getData();
|
||||
switch (e.getType()) {
|
||||
|
||||
case EditorCommon.EventType.ModelDispose:
|
||||
this.removeModel(this._models[modelId].model);
|
||||
this._onModelDisposing(modelData.model);
|
||||
// no more event processing
|
||||
return;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChanged:
|
||||
switch (data.changeType) {
|
||||
case EditorCommon.EventType.ModelContentChangedFlush:
|
||||
resultingEvents.push(this._mixinProperties({ type: e.getType() }, data, ['changeType', 'detail', 'versionId']));
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLinesDeleted:
|
||||
resultingEvents.push(this._mixinProperties({ type: e.getType() }, data, ['changeType', 'fromLineNumber', 'toLineNumber', 'versionId']));
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLinesInserted:
|
||||
resultingEvents.push(this._mixinProperties({ type: e.getType() }, data, ['changeType', 'fromLineNumber', 'toLineNumber', 'detail', 'versionId']));
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelContentChangedLineChanged:
|
||||
resultingEvents.push(this._mixinProperties({ type: e.getType() }, data, ['changeType', 'lineNumber', 'detail', 'versionId']));
|
||||
break;
|
||||
if (modelData.isSyncedToWorkers) {
|
||||
eventsForWorkers.contentChanged.push(<EditorCommon.IModelContentChangedEvent>data);
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelPropertiesChanged:
|
||||
resultingEvents.push(this._mixinProperties({ type: e.getType() }, data, ['properties']));
|
||||
if (modelData.isSyncedToWorkers) {
|
||||
eventsForWorkers.propertiesChanged = <EditorCommon.IModelPropertiesChangedEvent>data;
|
||||
}
|
||||
break;
|
||||
|
||||
case EditorCommon.EventType.ModelModeChanged:
|
||||
let modeChangedEvent = <EditorCommon.IModelModeChangedEvent>data;
|
||||
this._workerHelper.$onModelModeChanged(modelId, modeChangedEvent.oldMode.getId(), modeChangedEvent.newMode.getId());
|
||||
this._onModelModeChanged.fire(this._models[modelId].model, modeChangedEvent.oldMode.getId());
|
||||
if (modelData.isSyncedToWorkers) {
|
||||
// Forward mode change to all the workers
|
||||
this._workerHelper.$_acceptDidChangeModelMode(modelData.getModelId(), modeChangedEvent.oldMode.getId(), modeChangedEvent.newMode.getId());
|
||||
}
|
||||
this._onModelModeChanged.fire(modelData.model, modeChangedEvent.oldMode.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (resultingEvents.length > 0) {
|
||||
if (eventsForWorkers.contentChanged.length > 0 || eventsForWorkers.propertiesChanged) {
|
||||
// Forward events to all the workers
|
||||
this._sendModelEvents(this._models[modelId].model.getAssociatedResource(), resultingEvents);
|
||||
this._workerHelper.$_acceptModelEvents(modelData.getModelId(), eventsForWorkers);
|
||||
}
|
||||
}
|
||||
|
||||
private _mixinProperties(dst:any, src:any, properties:string[]): any {
|
||||
for (var i = 0; i < properties.length; i++) {
|
||||
dst[properties[i]] = src[properties[i]];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
||||
@Remotable.WorkerContext('ModelServiceWorkerHelper', ThreadAffinity.All)
|
||||
@@ -432,9 +388,9 @@ export class ModelServiceWorkerHelper {
|
||||
this._modeService = modeService;
|
||||
}
|
||||
|
||||
public $createModel(data:IRawModelData): TPromise<void> {
|
||||
public $_acceptNewModel(data:IRawModelData): TPromise<void> {
|
||||
// Create & insert the mirror model eagerly in the resource service
|
||||
var mirrorModel = new MirrorModel(this._resourceService, data.versionId, data.value, null, data.url, data.properties);
|
||||
let mirrorModel = new MirrorModel(this._resourceService, data.versionId, data.value, null, data.url, data.properties);
|
||||
this._resourceService.insert(mirrorModel.getAssociatedResource(), mirrorModel);
|
||||
|
||||
// Block worker execution until the mode is instantiated
|
||||
@@ -452,8 +408,8 @@ export class ModelServiceWorkerHelper {
|
||||
});
|
||||
}
|
||||
|
||||
public $onModelModeChanged(modelId:string, oldModeId:string, newModeId:string): TPromise<void> {
|
||||
var mirrorModel = this._resourceService.get(URI.parse(modelId));
|
||||
public $_acceptDidChangeModelMode(modelId:string, oldModeId:string, newModeId:string): TPromise<void> {
|
||||
let mirrorModel = this._resourceService.get(URI.parse(modelId));
|
||||
|
||||
// Block worker execution until the mode is instantiated
|
||||
return this._modeService.getOrCreateMode(newModeId).then((mode) => {
|
||||
@@ -470,31 +426,23 @@ export class ModelServiceWorkerHelper {
|
||||
});
|
||||
}
|
||||
|
||||
public $disposeModel(url:URL): void {
|
||||
var model = <MirrorModel>this._resourceService.get(url);
|
||||
public $_acceptDidDisposeModel(url:URL): void {
|
||||
let model = <MirrorModel>this._resourceService.get(url);
|
||||
this._resourceService.remove(url);
|
||||
if (model) {
|
||||
model.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public $onModelsEvents(events:IModelsEvents): void {
|
||||
let missingModels: string[] = [];
|
||||
Object.keys(events).forEach((strURL:string) => {
|
||||
var model = <MirrorModel>this._resourceService.get(new URL(strURL));
|
||||
if (!model) {
|
||||
missingModels.push(strURL);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.onEvents(events[strURL]);
|
||||
} catch (err) {
|
||||
Errors.onUnexpectedError(err);
|
||||
}
|
||||
});
|
||||
|
||||
if (missingModels.length > 0) {
|
||||
throw new Error('Received model events for missing models ' + missingModels.map(anonymize).join(' AND '));
|
||||
public $_acceptModelEvents(modelId: string, events:IMirrorModelEvents): void {
|
||||
let model = <MirrorModel>this._resourceService.get(new URL(modelId));
|
||||
if (!model) {
|
||||
throw new Error('Received model events for missing model ' + anonymize(modelId));
|
||||
}
|
||||
try {
|
||||
model.onEvents(events);
|
||||
} catch (err) {
|
||||
Errors.onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {TextModel} from 'vs/editor/common/model/textModel';
|
||||
import {LineMarker, TextModelWithMarkers} from 'vs/editor/common/model/textModelWithMarkers';
|
||||
import {ILineMarker} from 'vs/editor/common/model/modelLine';
|
||||
import {PluginHostDocument} from 'vs/workbench/api/common/pluginHostDocuments';
|
||||
import {MirrorModel} from 'vs/editor/common/model/mirrorModel';
|
||||
import {MirrorModel, IMirrorModelEvents} from 'vs/editor/common/model/mirrorModel';
|
||||
|
||||
suite('EditorModel - EditableTextModel._getInverseEdits', () => {
|
||||
|
||||
@@ -1194,8 +1194,11 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
|
||||
console.warn('Model version id did not advance between edits (1)');
|
||||
}
|
||||
mirrorModel1PrevVersionId = versionId;
|
||||
(<any>e).type = EditorCommon.EventType.ModelContentChanged;
|
||||
mirrorModel1.onEvents(<any[]>[e]);
|
||||
let mirrorModelEvents:IMirrorModelEvents = {
|
||||
propertiesChanged: null,
|
||||
contentChanged: [e]
|
||||
};
|
||||
mirrorModel1.onEvents(mirrorModelEvents);
|
||||
});
|
||||
|
||||
model.addListener(EditorCommon.EventType.ModelContentChanged2, (e:EditorCommon.IModelContentChangedEvent2) => {
|
||||
|
||||
@@ -21,6 +21,57 @@ function equalRange(left, right) {
|
||||
assert.ok(true, 'ranges');
|
||||
};
|
||||
|
||||
function contentChangedFlushEvent(detail: EditorCommon.IRawText): EditorCommon.IModelContentChangedFlushEvent {
|
||||
return {
|
||||
changeType: EditorCommon.EventType.ModelContentChangedFlush,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
versionId: 0,
|
||||
detail: detail
|
||||
};
|
||||
}
|
||||
|
||||
function contentChangedLinesDeletedEvent(fromLineNumber: number, toLineNumber: number): EditorCommon.IModelContentChangedLinesDeletedEvent {
|
||||
return {
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesDeleted,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
versionId: 0,
|
||||
fromLineNumber: fromLineNumber,
|
||||
toLineNumber: toLineNumber
|
||||
};
|
||||
}
|
||||
|
||||
function contentChangedLinesInsertedEvent(fromLineNumber: number, toLineNumber: number, detail: string): EditorCommon.IModelContentChangedLinesInsertedEvent {
|
||||
return {
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesInserted,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
versionId: 0,
|
||||
fromLineNumber: fromLineNumber,
|
||||
toLineNumber: toLineNumber,
|
||||
detail: detail
|
||||
};
|
||||
}
|
||||
|
||||
function contentChangedLineChanged(lineNumber: number, detail: string): EditorCommon.IModelContentChangedLineChangedEvent {
|
||||
return {
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLineChanged,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
versionId: 0,
|
||||
lineNumber: lineNumber,
|
||||
detail: detail
|
||||
};
|
||||
}
|
||||
|
||||
function mirrorModelEvents(contentChanged:EditorCommon.IModelContentChangedEvent[]): MirrorModel.IMirrorModelEvents {
|
||||
return {
|
||||
propertiesChanged: null,
|
||||
contentChanged: contentChanged
|
||||
};
|
||||
}
|
||||
|
||||
suite('Editor Model - MirrorModel', () => {
|
||||
|
||||
var mirrorModel:MirrorModel.MirrorModel;
|
||||
@@ -46,19 +97,16 @@ suite('Editor Model - MirrorModel', () => {
|
||||
assert.equal(mirrorModel.getLineStart(2), 6);
|
||||
assert.equal(mirrorModel.getLineStart(3), 12);
|
||||
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedFlush,
|
||||
detail: {
|
||||
lines: [
|
||||
'foo',
|
||||
'bar'
|
||||
],
|
||||
BOM: '',
|
||||
EOL: '\n'
|
||||
}
|
||||
};
|
||||
mirrorModel.onEvents([e]);
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedFlushEvent({
|
||||
length: -1,
|
||||
lines: [
|
||||
'foo',
|
||||
'bar'
|
||||
],
|
||||
BOM: '',
|
||||
EOL: '\n'
|
||||
})]));
|
||||
|
||||
assert.equal(mirrorModel.getLineStart(1), 0);
|
||||
assert.equal(mirrorModel.getLineStart(2), 4);
|
||||
});
|
||||
@@ -170,14 +218,9 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
});
|
||||
|
||||
test('delete single line', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesDeleted,
|
||||
fromLineNumber: 3,
|
||||
toLineNumber: 3
|
||||
};
|
||||
assert.equal(mirrorModel.getLineContent(3), 'line three');
|
||||
mirrorModel.onEvents([e]);
|
||||
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(3, 3)]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(3), 'line four');
|
||||
var words = mirrorModel.getAllWords();
|
||||
@@ -191,13 +234,8 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
});
|
||||
|
||||
test('delete multiple lines', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesDeleted,
|
||||
fromLineNumber: 1,
|
||||
toLineNumber: 2
|
||||
};
|
||||
mirrorModel.onEvents([e]);
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(1, 2)]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'line three');
|
||||
assert.equal(mirrorModel.getLineContent(2), 'line four');
|
||||
var words = mirrorModel.getAllWords();
|
||||
@@ -220,13 +258,8 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
});
|
||||
|
||||
test('delete all lines', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesDeleted,
|
||||
fromLineNumber: 1,
|
||||
toLineNumber: 4
|
||||
};
|
||||
mirrorModel.onEvents([e]);
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesDeletedEvent(1, 4)]));
|
||||
|
||||
var words = mirrorModel.getAllWords();
|
||||
assert.equal(words.length, 0);
|
||||
var wordsWithRanges = mirrorModel.getAllWordsWithRange();
|
||||
@@ -234,16 +267,10 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
});
|
||||
|
||||
test('add single lines', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesInserted,
|
||||
fromLineNumber: 1,
|
||||
toLineNumber: 1,
|
||||
detail: 'foo bar\nbar foo'
|
||||
};
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'line one');
|
||||
mirrorModel.onEvents([e]);
|
||||
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesInsertedEvent(1, 1, 'foo bar\nbar foo')]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'foo bar');
|
||||
assert.equal(mirrorModel.getLineContent(2), 'line one');
|
||||
|
||||
@@ -257,16 +284,10 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
|
||||
|
||||
test('add multiple lines', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLinesInserted,
|
||||
fromLineNumber: 1,
|
||||
toLineNumber: 2,
|
||||
detail: 'foo bar\nbar foo'
|
||||
};
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'line one');
|
||||
mirrorModel.onEvents([e]);
|
||||
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLinesInsertedEvent(1, 2, 'foo bar\nbar foo')]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'foo bar');
|
||||
assert.equal(mirrorModel.getLineContent(2), 'bar foo');
|
||||
assert.equal(mirrorModel.getLineContent(3), 'line one');
|
||||
@@ -284,16 +305,11 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
});
|
||||
|
||||
test('change line', () => {
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedLineChanged,
|
||||
lineNumber: 1,
|
||||
detail: 'foobar'
|
||||
};
|
||||
assert.equal(mirrorModel.getLineContent(1), 'line one');
|
||||
var wordsWithRanges = mirrorModel.getAllWordsWithRange();
|
||||
assert.equal(wordsWithRanges.length, 8);
|
||||
mirrorModel.onEvents([e]);
|
||||
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedLineChanged(1, 'foobar')]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'foobar');
|
||||
wordsWithRanges = mirrorModel.getAllWordsWithRange();
|
||||
@@ -305,19 +321,17 @@ suite('Editor Model - MirrorModel Eventing', () => {
|
||||
test('flush model', () => {
|
||||
assert.equal(mirrorModel.getLineContent(1), 'line one');
|
||||
assert.equal(mirrorModel.getLineContent(2), 'line two');
|
||||
var e = {
|
||||
type: EditorCommon.EventType.ModelContentChanged,
|
||||
changeType: EditorCommon.EventType.ModelContentChangedFlush,
|
||||
detail: {
|
||||
lines: [
|
||||
'foo',
|
||||
'bar'
|
||||
],
|
||||
BOM: '',
|
||||
EOL: '\n'
|
||||
}
|
||||
};
|
||||
mirrorModel.onEvents([e]);
|
||||
|
||||
mirrorModel.onEvents(mirrorModelEvents([contentChangedFlushEvent({
|
||||
length: -1,
|
||||
lines: [
|
||||
'foo',
|
||||
'bar'
|
||||
],
|
||||
BOM: '',
|
||||
EOL: '\n'
|
||||
})]));
|
||||
|
||||
assert.equal(mirrorModel.getLineContent(1), 'foo');
|
||||
assert.equal(mirrorModel.getLineContent(2), 'bar');
|
||||
var wordsWithRanges = mirrorModel.getAllWordsWithRange();
|
||||
|
||||
@@ -84,4 +84,8 @@ class Mode implements modes.IMode {
|
||||
public getId(): string {
|
||||
return "testMode";
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ export class Mode implements modes.IMode {
|
||||
public getId(): string {
|
||||
return "testMode";
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +118,10 @@ export class SwitchingMode implements modes.IMode {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
|
||||
public addSupportChangedListener(callback: (e: EditorCommon.IModeSupportChangedEvent) => void): IDisposable {
|
||||
return EmptyDisposable;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,25 @@
|
||||
import modes = require('vs/editor/common/modes');
|
||||
import {Arrays} from 'vs/editor/common/core/arrays';
|
||||
|
||||
class SimpleTokenTypeClassificationMode implements modes.IMode {
|
||||
|
||||
private _id:string;
|
||||
public tokenTypeClassificationSupport: modes.ITokenTypeClassificationSupport;
|
||||
|
||||
constructor(id:string, tokenTypeClassificationSupport: modes.ITokenTypeClassificationSupport) {
|
||||
this._id = id;
|
||||
this.tokenTypeClassificationSupport = tokenTypeClassificationSupport;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export function createMockMode(id:string, wordRegExp:RegExp = null):modes.IMode {
|
||||
var tokenTypeClassificationSupport: modes.ITokenTypeClassificationSupport;
|
||||
if (wordRegExp) {
|
||||
@@ -14,10 +33,7 @@ export function createMockMode(id:string, wordRegExp:RegExp = null):modes.IMode
|
||||
getWordDefinition: () => wordRegExp
|
||||
};
|
||||
}
|
||||
return {
|
||||
getId: () => id,
|
||||
tokenTypeClassificationSupport: tokenTypeClassificationSupport
|
||||
};
|
||||
return new SimpleTokenTypeClassificationMode(id, tokenTypeClassificationSupport);
|
||||
}
|
||||
|
||||
export interface TokenText {
|
||||
|
||||
@@ -87,11 +87,28 @@ export interface IOnEnterAsserter {
|
||||
indentsOutdents(oneLineAboveText:string, beforeText:string, afterText:string): void;
|
||||
}
|
||||
|
||||
class SimpleMode implements modes.IMode {
|
||||
|
||||
private _id:string;
|
||||
|
||||
constructor(id:string) {
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export function createOnEnterAsserter(modeId:string, onEnterSupport: modes.IOnEnterSupport): IOnEnterAsserter {
|
||||
var assertOne = (oneLineAboveText:string, beforeText:string, afterText:string, expected: modes.IndentAction) => {
|
||||
var model = new Model(
|
||||
[ oneLineAboveText, beforeText + afterText ].join('\n'),
|
||||
{ getId: () => modeId }
|
||||
new SimpleMode(modeId)
|
||||
);
|
||||
var actual = onEnterSupport.onEnter(model, { lineNumber: 2, column: beforeText.length + 1 });
|
||||
if (expected === modes.IndentAction.None) {
|
||||
@@ -130,9 +147,7 @@ export function executeMonarchTokenizationTests(name:string, language:monarchTyp
|
||||
|
||||
var modeService = servicesUtil.createMockModeService();
|
||||
|
||||
var tokenizationSupport = monarchLexer.createTokenizationSupport(modeService, {
|
||||
getId: () => 'mock.mode'
|
||||
}, lexer);
|
||||
var tokenizationSupport = monarchLexer.createTokenizationSupport(modeService, new SimpleMode('mock.mode'), lexer);
|
||||
|
||||
executeTests(tokenizationSupport, tests);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ export class TestingMode implements modes.IMode {
|
||||
public getId():string {
|
||||
return 'testing';
|
||||
}
|
||||
|
||||
public toSimplifiedMode(): modes.IMode {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class AbstractIndentingMode extends TestingMode {
|
||||
|
||||
@@ -62,7 +62,6 @@ function createModelService(): IModelService {
|
||||
onModelAdded: undefined,
|
||||
onModelRemoved: undefined,
|
||||
onModelModeChanged: undefined,
|
||||
removeModel: undefined,
|
||||
destroyModel: undefined
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user