Skip to content

Commit

Permalink
Reading file that is constantly being modified causes a crash (micros…
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Mar 16, 2016
1 parent bbe5685 commit 68bae9c
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 70 deletions.
5 changes: 5 additions & 0 deletions src/vs/editor/common/editorCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,8 @@ export interface ITextModel {

toRawText(): IRawText;

equals(other:IRawText): boolean;

/**
* Get the text in a certain range.
* @param range The range describing what text to get.
Expand Down Expand Up @@ -1859,6 +1861,9 @@ export interface IModel extends IEditableTextModel, ITextModelWithMarkers, IToke
setValue(newValue:string, newMode?:IMode): void;
setValue(newValue:string, newModePromise:TPromise<IMode>): void;

setValueFromRawText(newValue:IRawText, newMode?:IMode): void;
setValueFromRawText(newValue:IRawText, newModePromise:TPromise<IMode>): void;

onBeforeAttached(): void;

onBeforeDetached(): void;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/common/model/editableTextModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
super.dispose();
}

_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:string): void {
_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:editorCommon.IRawText): void {
super._resetValue(e, newValue);

// Destroy my edit history and settings
Expand Down
67 changes: 58 additions & 9 deletions src/vs/editor/common/model/textModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
_EOL:string;
_isDisposed:boolean;
_isDisposing:boolean;
private _options: editorCommon.ITextModelResolvedOptions;
protected _options: editorCommon.ITextModelResolvedOptions;

private _versionId:number;
/**
Expand Down Expand Up @@ -217,13 +217,9 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
}
}

_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:string): void {
this._constructLines(TextModel.toRawText(newValue, {
tabSize: this._options.tabSize,
insertSpaces: this._options.insertSpaces,
detectIndentation: false,
defaultEOL: this._options.defaultEOL
}));
_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:editorCommon.IRawText): void {
this._constructLines(newValue);

this._increaseVersionId();

e.detail = this.toRawText();
Expand All @@ -240,10 +236,44 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
};
}

public setValue(newValue:string): void {
public equals(other: editorCommon.IRawText): boolean {
if (this._BOM !== other.BOM) {
return false;
}
if (this._EOL !== other.EOL) {
return false;
}
if (this._lines.length !== other.lines.length) {
return false;
}
for (let i = 0, len = this._lines.length; i < len; i++) {
if (this._lines[i].text !== other.lines[i]) {
return false;
}
}
return true;
}

public setValue(value:string): void {
if (this._isDisposed) {
throw new Error('TextModel.setValue: Model is disposed');
}
let rawText: editorCommon.IRawText = null;
if (value !== null) {
rawText = TextModel.toRawText(value, {
tabSize: this._options.tabSize,
insertSpaces: this._options.insertSpaces,
detectIndentation: false,
defaultEOL: this._options.defaultEOL
});
}
this.setValueFromRawText(rawText);
}

public setValueFromRawText(newValue:editorCommon.IRawText): void {
if (this._isDisposed) {
throw new Error('TextModel.setValueFromRawText: Model is disposed');
}

if (newValue === null) {
// There's nothing to do
Expand All @@ -254,6 +284,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
var endLineNumber = this.getLineCount();
var endColumn = this.getLineMaxColumn(endLineNumber);
var e = this._createContentChangedFlushEvent();

this._resetValue(e, newValue);
this._emitModelContentChangedFlushEvent(e);
this._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false);
Expand Down Expand Up @@ -892,3 +923,21 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
return counter;
}
}

export class RawText {

public static fromString(rawText:string, opts:editorCommon.ITextModelCreationOptions): editorCommon.IRawText {
return TextModel.toRawText(rawText, opts);
}

public static fromStringWithModelOptions(rawText:string, model:editorCommon.IModel): editorCommon.IRawText {
let opts = model.getOptions();
return TextModel.toRawText(rawText, {
tabSize: opts.tabSize,
insertSpaces: opts.insertSpaces,
detectIndentation: false,
defaultEOL: opts.defaultEOL
});
}

}
2 changes: 1 addition & 1 deletion src/vs/editor/common/model/textModelWithDecorations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class TextModelWithDecorations extends TextModelWithTrackedRanges impleme
super.dispose();
}

_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:string): void {
_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:editorCommon.IRawText): void {
super._resetValue(e, newValue);

// Destroy all my decorations
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/common/model/textModelWithMarkers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class TextModelWithMarkers extends TextModelWithTokens implements ITextMo
super.dispose();
}

_resetValue(e:IModelContentChangedFlushEvent, newValue:string): void {
_resetValue(e:IModelContentChangedFlushEvent, newValue:IRawText): void {
super._resetValue(e, newValue);

// Destroy all my markers
Expand Down
24 changes: 21 additions & 3 deletions src/vs/editor/common/model/textModelWithTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
return new FullModelRetokenizer(retokenizePromise, this);
}

_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:string): void {
_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:editorCommon.IRawText): void {
super._resetValue(e, newValue);
// Cancel tokenization, clear all tokens and begin tokenizing
this._resetTokenizationState();
Expand Down Expand Up @@ -456,9 +456,27 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
if (this._isDisposed) {
throw new Error('TextModelWithTokens.setValue: Model is disposed');
}
let rawText: editorCommon.IRawText = null;
if (value !== null) {
rawText = TextModel.toRawText(value, {
tabSize: this._options.tabSize,
insertSpaces: this._options.insertSpaces,
detectIndentation: false,
defaultEOL: this._options.defaultEOL
});
}
this.setValueFromRawText(rawText, newModeOrPromise);
}

public setValueFromRawText(value:editorCommon.IRawText, newMode?:IMode): void;
public setValueFromRawText(value:editorCommon.IRawText, newModePromise?:TPromise<IMode>): void;
public setValueFromRawText(value:editorCommon.IRawText, newModeOrPromise:any=null): void {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.setValueFromRawText: Model is disposed');
}

if (value !== null) {
super.setValue(value);
super.setValueFromRawText(value);
}

if (newModeOrPromise) {
Expand Down Expand Up @@ -501,7 +519,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
// There's nothing to do
return;
}
this.setValue(null, newModeOrPromise);
this.setValueFromRawText(null, newModeOrPromise);
}

public getModeAtPosition(_lineNumber:number, _column:number): IMode {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/common/model/textModelWithTrackedRanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class TextModelWithTrackedRanges extends TextModelWithMarkers implements
super.dispose();
}

_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:string): void {
_resetValue(e:editorCommon.IModelContentChangedFlushEvent, newValue:editorCommon.IRawText): void {
super._resetValue(e, newValue);

// Destroy all my tracked ranges
Expand Down
37 changes: 13 additions & 24 deletions src/vs/workbench/common/editor/textEditorModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
'use strict';

import {TPromise} from 'vs/base/common/winjs.base';
import types = require('vs/base/common/types');
import {EndOfLinePreference, IModel, EventType} from 'vs/editor/common/editorCommon';
import {IMode} from 'vs/editor/common/modes';
import {EditorModel} from 'vs/workbench/common/editor';
import URI from 'vs/base/common/uri';
import {NullMode} from 'vs/editor/common/modes/nullMode';
import {ITextEditorModel} from 'vs/platform/editor/common/editor';
import {IModeService} from 'vs/editor/common/services/modeService';
import {IModelService} from 'vs/editor/common/services/modelService';
import {RawText} from 'vs/editor/common/model/textModel';

/**
* The base text editor model leverages the monaco code editor model. This class is only intended to be subclassed and not instantiated.
Expand Down Expand Up @@ -98,32 +97,22 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
}

/**
* Updates the text editor model with the provided value and mime (can be comma separated for multiple values).
*
* This is a no-op if neither the value did not change nor the mime.
* Updates the text editor model with the provided value. If the value is the same as the model has, this is a no-op.
*/
protected updateTextEditorModel(newValue?: string, newMime?: string): void {
// Detect content changes
let currentModelValue = this.getValue();
let valueChanged = (!types.isUndefinedOrNull(newValue) && currentModelValue !== newValue);

// Detect mode changes
let modeChanged = false;
if (!types.isUndefinedOrNull(newMime)) {
let modeId = this.modeService.getModeId(newMime);
let currentMode = this.textEditorModel.getMode();
if (currentMode && currentMode.getId() !== NullMode.ID && modeId) {
let currentModeId = currentMode.getId();
modeChanged = (currentModeId !== modeId);
}
protected updateTextEditorModel(newValue: string): void {
if (!this.textEditorModel) {
return;
}

// Apply either content or mode or both
if (valueChanged) {
this.textEditorModel.setValue(newValue, modeChanged ? this.getOrCreateMode(this.modeService, newMime) : undefined);
} else if (modeChanged) {
this.textEditorModel.setMode(this.getOrCreateMode(this.modeService, newMime));
let rawText = RawText.fromStringWithModelOptions(newValue, this.textEditorModel);

// Return early if the text is already set in that form
if (this.textEditorModel.equals(rawText)) {
return;
}

// Otherwise update model
this.textEditorModel.setValueFromRawText(rawText);
}

/**
Expand Down
36 changes: 6 additions & 30 deletions src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletServi
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {KeyMod, KeyCode} from 'vs/base/common/keyCodes';
import {IModelService} from 'vs/editor/common/services/modelService';
import {TextModel} from 'vs/editor/common/model/textModel';
import {RawText} from 'vs/editor/common/model/textModel';
import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService';
import URI from 'vs/base/common/uri';

Expand Down Expand Up @@ -204,22 +204,6 @@ class DirtyDiffModelDecorator {
.done(null, errors.onUnexpectedError);
}

private static _stringArrEquals(a:string[], b:string[]): boolean {
if (a.length !== b.length) {
return false;
}
for (let i = 0, len = a.length; i < len; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}

private static _equals(a:common.IRawText, b:common.IRawText): boolean {
return this._stringArrEquals(a.lines, b.lines);
}

private diffOriginalContents(): winjs.TPromise<void> {
return this.getOriginalContents()
.then(contents => {
Expand All @@ -235,26 +219,18 @@ class DirtyDiffModelDecorator {

let originalModel = this.modelService.getModel(this._originalContentsURI);
if (originalModel) {
let originalRawText = originalModel.toRawText();
let contentsRawText = TextModel.toRawText(contents, {
tabSize: originalRawText.options.tabSize,
insertSpaces: originalRawText.options.insertSpaces,
detectIndentation: false,
defaultEOL: originalRawText.options.defaultEOL
});
let contentsRawText = RawText.fromStringWithModelOptions(contents, originalModel);

// return early if nothing has changed
if (DirtyDiffModelDecorator._equals(originalRawText, contentsRawText)) {
if (originalModel.equals(contentsRawText)) {
return winjs.TPromise.as(null);
}
}

if (!originalModel) {
// we already have the original contents
originalModel.setValueFromRawText(contentsRawText);
} else {
// this is the first time we load the original contents
this.modelService.createModel(contents, null, this._originalContentsURI);
} else {
// we already have the original contents
originalModel.setValue(contents);
}

return this.triggerDiff();
Expand Down

0 comments on commit 68bae9c

Please sign in to comment.