Skip to content

Commit d7dbecc

Browse files
committed
prepare for weak references - use ExtHostDocumentData with a TextDocument property instead of having just ExtHostDocument
1 parent d786468 commit d7dbecc

2 files changed

Lines changed: 102 additions & 113 deletions

File tree

src/vs/workbench/api/common/extHostDocuments.ts

Lines changed: 77 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ export class ExtHostModelService {
6666
private _onDidSaveDocumentEventEmitter: Emitter<vscode.TextDocument>;
6767
public onDidSaveDocument: Event<vscode.TextDocument>;
6868

69-
private _documents: { [modelUri: string]: ExtHostDocumentData; };
70-
private _loadingDocuments: { [modelUri: string]: TPromise<ExtHostDocumentData> };
69+
private _documentData: { [modelUri: string]: ExtHostDocumentData; };
70+
private _documentLoader: { [modelUri: string]: TPromise<ExtHostDocumentData> };
7171
private _documentContentProviders: { [scheme: string]: vscode.TextDocumentContentProvider };
7272

7373
private _proxy: MainThreadDocuments;
@@ -87,15 +87,15 @@ export class ExtHostModelService {
8787
this._onDidSaveDocumentEventEmitter = new Emitter<vscode.TextDocument>();
8888
this.onDidSaveDocument = this._onDidSaveDocumentEventEmitter.event;
8989

90-
this._documents = Object.create(null);
91-
this._loadingDocuments = Object.create(null);
90+
this._documentData = Object.create(null);
91+
this._documentLoader = Object.create(null);
9292
this._documentContentProviders = Object.create(null);
9393
}
9494

9595
public getDocuments(): vscode.TextDocument[] {
9696
let r: vscode.TextDocument[] = [];
97-
for (let key in this._documents) {
98-
r.push(this._documents[key]);
97+
for (let key in this._documentData) {
98+
r.push(this._documentData[key].document);
9999
}
100100
return r;
101101
}
@@ -104,7 +104,10 @@ export class ExtHostModelService {
104104
if (!resource) {
105105
return null;
106106
}
107-
return this._documents[resource.toString()] || null;
107+
const data = this._documentData[resource.toString()];
108+
if (data) {
109+
return data.document;
110+
}
108111
}
109112

110113
public openDocument(uriOrFileName: vscode.Uri | string): TPromise<vscode.TextDocument> {
@@ -118,23 +121,24 @@ export class ExtHostModelService {
118121
throw new Error('illegal argument - uriOrFileName');
119122
}
120123

121-
let cached = this._documents[uri.toString()];
124+
let cached = this._documentData[uri.toString()];
122125
if (cached) {
123-
return TPromise.as(cached);
126+
return TPromise.as(cached.document);
124127
}
125128

126-
let promise = this._loadingDocuments[uri.toString()];
127-
if (promise) {
128-
return promise;
129+
let promise = this._documentLoader[uri.toString()];
130+
if (!promise) {
131+
promise = this._proxy._tryOpenDocument(uri).then(() => {
132+
delete this._documentLoader[uri.toString()];
133+
return this._documentData[uri.toString()];
134+
}, err => {
135+
delete this._documentLoader[uri.toString()];
136+
return TPromise.wrapError(err);
137+
});
138+
this._documentLoader[uri.toString()] = promise;
129139
}
130140

131-
return this._loadingDocuments[uri.toString()] = this._proxy._tryOpenDocument(uri).then(() => {
132-
delete this._loadingDocuments[uri.toString()];
133-
return this._documents[uri.toString()];
134-
}, err => {
135-
delete this._loadingDocuments[uri.toString()];
136-
return TPromise.wrapError(err);
137-
});
141+
return promise.then(data => data.document);
138142
}
139143

140144
public registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider): vscode.Disposable {
@@ -158,58 +162,58 @@ export class ExtHostModelService {
158162
});
159163
}
160164

161-
public _acceptModelAdd(data:IModelAddedData): void {
162-
let document = new ExtHostDocumentData(this._proxy, data.url, data.value.lines, data.value.EOL, data.modeId, data.versionId, data.isDirty);
163-
let key = document.uri.toString();
164-
if (this._documents[key]) {
165+
public _acceptModelAdd(initData:IModelAddedData): void {
166+
let data = new ExtHostDocumentData(this._proxy, initData.url, initData.value.lines, initData.value.EOL, initData.modeId, initData.versionId, initData.isDirty);
167+
let key = data.document.uri.toString();
168+
if (this._documentData[key]) {
165169
throw new Error('Document `' + key + '` already exists.');
166170
}
167-
this._documents[key] = document;
168-
this._onDidAddDocumentEventEmitter.fire(document);
171+
this._documentData[key] = data;
172+
this._onDidAddDocumentEventEmitter.fire(data.document);
169173
}
170174

171175
public _acceptModelModeChanged(url: URI, oldModeId:string, newModeId:string): void {
172-
let document = this._documents[url.toString()];
176+
let data = this._documentData[url.toString()];
173177

174178
// Treat a mode change as a remove + add
175179

176-
this._onDidRemoveDocumentEventEmitter.fire(document);
177-
document._acceptLanguageId(newModeId);
178-
this._onDidAddDocumentEventEmitter.fire(document);
180+
this._onDidRemoveDocumentEventEmitter.fire(data.document);
181+
data._acceptLanguageId(newModeId);
182+
this._onDidAddDocumentEventEmitter.fire(data.document);
179183
}
180184

181185
public _acceptModelSaved(url: URI): void {
182-
let document = this._documents[url.toString()];
183-
document._acceptIsDirty(false);
184-
this._onDidSaveDocumentEventEmitter.fire(document);
186+
let data = this._documentData[url.toString()];
187+
data._acceptIsDirty(false);
188+
this._onDidSaveDocumentEventEmitter.fire(data.document);
185189
}
186190

187191
public _acceptModelDirty(url: URI): void {
188-
let document = this._documents[url.toString()];
192+
let document = this._documentData[url.toString()];
189193
document._acceptIsDirty(true);
190194
}
191195

192196
public _acceptModelReverted(url: URI): void {
193-
let document = this._documents[url.toString()];
197+
let document = this._documentData[url.toString()];
194198
document._acceptIsDirty(false);
195199
}
196200

197201
public _acceptModelRemoved(url: URI): void {
198202
let key = url.toString();
199-
if (!this._documents[key]) {
203+
if (!this._documentData[key]) {
200204
throw new Error('Document `' + key + '` does not exist.');
201205
}
202-
let document = this._documents[key];
203-
delete this._documents[key];
204-
this._onDidRemoveDocumentEventEmitter.fire(document);
205-
document.dispose();
206+
let data = this._documentData[key];
207+
delete this._documentData[key];
208+
this._onDidRemoveDocumentEventEmitter.fire(data.document);
209+
data.dispose();
206210
}
207211

208212
public _acceptModelChanged(url: URI, events: EditorCommon.IModelContentChangedEvent2[]): void {
209-
let document = this._documents[url.toString()];
210-
document.onEvents(events);
213+
let data = this._documentData[url.toString()];
214+
data.onEvents(events);
211215
this._onDidChangeDocumentEventEmitter.fire({
212-
document: document,
216+
document: data.document,
213217
contentChanges: events.map((e) => {
214218
return {
215219
range: TypeConverters.toRange(e.range),
@@ -221,12 +225,13 @@ export class ExtHostModelService {
221225
}
222226
}
223227

224-
export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocument {
228+
export class ExtHostDocumentData extends MirrorModel2 {
225229

226230
private _proxy: MainThreadDocuments;
227231
private _languageId: string;
228232
private _isDirty: boolean;
229233
private _textLines: vscode.TextLine[];
234+
private _document: vscode.TextDocument;
230235

231236
constructor(proxy: MainThreadDocuments, uri: URI, lines: string[], eol: string,
232237
languageId: string, versionId: number, isDirty: boolean) {
@@ -244,32 +249,28 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
244249
super.dispose();
245250
}
246251

247-
get uri(): URI {
248-
return this._uri;
249-
}
250-
251-
get fileName(): string {
252-
return this._uri.fsPath;
253-
}
254-
255-
get isUntitled(): boolean {
256-
return this._uri.scheme !== 'file';
257-
}
258-
259-
get languageId(): string {
260-
return this._languageId;
261-
}
262-
263-
get version(): number {
264-
return this._versionId;
265-
}
266-
267-
get isDirty(): boolean {
268-
return this._isDirty;
269-
}
270-
271-
save(): Thenable<boolean> {
272-
return this._proxy._trySaveDocument(this._uri);
252+
get document(): vscode.TextDocument {
253+
if (!this._document) {
254+
const document = this;
255+
this._document = {
256+
get uri() { return document._uri },
257+
get fileName() { return document._uri.fsPath },
258+
get isUntitled() { return document._uri.scheme !== 'file' },
259+
get languageId() { return document._languageId },
260+
get version() { return document._versionId },
261+
get isDirty() { return document._isDirty },
262+
save() { return document._proxy._trySaveDocument(document._uri) },
263+
getText(range?) { return range ? document._getTextInRange(range) : document.getText() },
264+
get lineCount() { return document._lines.length },
265+
lineAt(lineOrPos) { return document.lineAt(lineOrPos) },
266+
offsetAt(pos) { return document.offsetAt(pos) },
267+
positionAt(offset) { return document.positionAt(offset) },
268+
validateRange(ran) { return document.validateRange(ran) },
269+
validatePosition(pos) { return document.validatePosition(pos) },
270+
getWordRangeAtPosition(pos){ return document.getWordRangeAtPosition(pos)}
271+
}
272+
}
273+
return this._document;
273274
}
274275

275276
_acceptLanguageId(newLanguageId:string): void {
@@ -280,15 +281,7 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
280281
this._isDirty = isDirty;
281282
}
282283

283-
getText(range?: Range): string {
284-
if (range) {
285-
return this._getTextInRange(range);
286-
} else {
287-
return super.getText();
288-
}
289-
}
290-
291-
private _getTextInRange(_range: Range): string {
284+
private _getTextInRange(_range: vscode.Range): string {
292285
let range = this.validateRange(_range);
293286

294287
if (range.isEmpty) {
@@ -313,10 +306,6 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
313306
return resultLines.join(lineEnding);
314307
}
315308

316-
get lineCount(): number {
317-
return this._lines.length;
318-
}
319-
320309
lineAt(lineOrPosition: number | vscode.Position): vscode.TextLine {
321310

322311
let line: number;
@@ -353,13 +342,13 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
353342
return result;
354343
}
355344

356-
offsetAt(position: Position): number {
345+
offsetAt(position: vscode.Position): number {
357346
position = this.validatePosition(position);
358347
this._ensureLineStarts();
359348
return this._lineStarts.getAccumulatedValue(position.line - 1) + position.character;
360349
}
361350

362-
positionAt(offset: number): Position {
351+
positionAt(offset: number): vscode.Position {
363352
offset = Math.floor(offset);
364353
offset = Math.max(0, offset);
365354

@@ -375,7 +364,7 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
375364

376365
// ---- range math
377366

378-
validateRange(range:Range): Range {
367+
validateRange(range:vscode.Range): vscode.Range {
379368
if (!(range instanceof Range)) {
380369
throw new Error('Invalid argument');
381370
}
@@ -386,10 +375,10 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
386375
if (start === range.start && end === range.end) {
387376
return range;
388377
}
389-
return new Range(start, end);
378+
return new Range(start.line, start.character, end.line, end.character);
390379
}
391380

392-
validatePosition(position:Position): Position {
381+
validatePosition(position:vscode.Position): vscode.Position {
393382
if (!(position instanceof Position)) {
394383
throw new Error('Invalid argument');
395384
}
@@ -424,7 +413,7 @@ export class ExtHostDocumentData extends MirrorModel2 implements vscode.TextDocu
424413
return new Position(line, character);
425414
}
426415

427-
getWordRangeAtPosition(_position:Position): Range {
416+
getWordRangeAtPosition(_position: vscode.Position): vscode.Range {
428417
let position = this.validatePosition(_position);
429418

430419
let wordAtText = WordHelper._getWordAtText(

0 commit comments

Comments
 (0)