mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 02:28:34 +01:00
introduce the concept fo ContentProvider to the ResourceEditorInput
Instead of just letting the API layer know about content provider we must push it lower because only than we can handle uri's opaque.
This commit is contained in:
@@ -24,8 +24,8 @@ import * as vscode from 'vscode';
|
||||
import {WordHelper} from 'vs/editor/common/model/textModelWithTokensHelpers';
|
||||
import {IFileService} from 'vs/platform/files/common/files';
|
||||
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import {ResourceEditorInput} from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import {asWinJsPromise} from 'vs/base/common/async';
|
||||
import {IModeService} from 'vs/editor/common/services/modeService';
|
||||
import * as weak from 'weak';
|
||||
|
||||
export interface IModelAddedData {
|
||||
@@ -134,6 +134,7 @@ export class ExtHostModelService {
|
||||
throw new Error(`scheme '${scheme}' already registered`);
|
||||
}
|
||||
this._documentContentProviders[scheme] = provider;
|
||||
this._proxy.$registerTextContentProvider(scheme);
|
||||
|
||||
let subscription: IDisposable;
|
||||
if (typeof provider.onDidChange === 'function') {
|
||||
@@ -146,6 +147,7 @@ export class ExtHostModelService {
|
||||
});
|
||||
}
|
||||
return new Disposable(() => {
|
||||
this._proxy.$unregisterTextContentProvider(scheme);
|
||||
delete this._documentContentProviders[scheme];
|
||||
if (subscription) {
|
||||
subscription.dispose();
|
||||
@@ -166,8 +168,14 @@ export class ExtHostModelService {
|
||||
});
|
||||
}
|
||||
|
||||
$isDocumentReferenced(uri: URI): TPromise<boolean> {
|
||||
return TPromise.as(this.getDocumentData(uri).isDocumentReferenced);
|
||||
$getUnferencedDocuments(): TPromise<URI[]> {
|
||||
const result: URI[] = [];
|
||||
for (let key in this._documentData) {
|
||||
if (!this._documentData[key].isDocumentReferenced) {
|
||||
result.push(URI.parse(key));
|
||||
}
|
||||
}
|
||||
return TPromise.as(result);
|
||||
}
|
||||
|
||||
public _acceptModelAdd(initData: IModelAddedData): void {
|
||||
@@ -449,7 +457,6 @@ export class ExtHostDocumentData extends MirrorModel2 {
|
||||
@Remotable.MainContext('MainThreadDocuments')
|
||||
export class MainThreadDocuments {
|
||||
private _modelService: IModelService;
|
||||
private _modeService: IModeService;
|
||||
private _textFileService: ITextFileService;
|
||||
private _editorService: IWorkbenchEditorService;
|
||||
private _fileService: IFileService;
|
||||
@@ -458,11 +465,11 @@ export class MainThreadDocuments {
|
||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||
private _proxy: ExtHostModelService;
|
||||
private _modelIsSynced: { [modelId: string]: boolean; };
|
||||
private _resourceContentProvider: { [scheme: string]: IDisposable };
|
||||
|
||||
constructor(
|
||||
@IThreadService threadService: IThreadService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IEventService eventService: IEventService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
|
||||
@@ -470,7 +477,6 @@ export class MainThreadDocuments {
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService
|
||||
) {
|
||||
this._modelService = modelService;
|
||||
this._modeService = modeService;
|
||||
this._textFileService = textFileService;
|
||||
this._editorService = editorService;
|
||||
this._fileService = fileService;
|
||||
@@ -493,7 +499,11 @@ export class MainThreadDocuments {
|
||||
this._proxy._acceptModelDirty(e.getAfter().resource);
|
||||
}));
|
||||
|
||||
const handle = setInterval(() => this._runDocumentCleanup(), 30 * 1000);
|
||||
this._toDispose.push({ dispose() { clearInterval(handle) } });
|
||||
|
||||
this._modelToDisposeMap = Object.create(null);
|
||||
this._resourceContentProvider = Object.create(null);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -571,14 +581,12 @@ export class MainThreadDocuments {
|
||||
|
||||
let promise: TPromise<boolean>;
|
||||
switch (uri.scheme) {
|
||||
case 'file':
|
||||
promise = this._handleFileScheme(uri);
|
||||
break;
|
||||
case 'untitled':
|
||||
promise = this._handleUnititledScheme(uri);
|
||||
break;
|
||||
case 'file':
|
||||
default:
|
||||
promise = this._handleAnyScheme(uri);
|
||||
promise = this._handleAsResourceInput(uri);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -591,7 +599,7 @@ export class MainThreadDocuments {
|
||||
});
|
||||
}
|
||||
|
||||
private _handleFileScheme(uri: URI): TPromise<boolean> {
|
||||
private _handleAsResourceInput(uri: URI): TPromise<boolean> {
|
||||
return this._editorService.resolveEditorModel({ resource: uri }).then(model => {
|
||||
return !!model;
|
||||
});
|
||||
@@ -617,46 +625,46 @@ export class MainThreadDocuments {
|
||||
|
||||
// --- virtual document logic
|
||||
|
||||
private _handleAnyScheme(uri: URI): TPromise<boolean> {
|
||||
|
||||
if (this._modelService.getModel(uri)) {
|
||||
return TPromise.as(true);
|
||||
}
|
||||
|
||||
return this._proxy.$provideTextDocumentContent(uri).then(value => {
|
||||
|
||||
// create document from string
|
||||
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
|
||||
const mode = this._modeService.getOrCreateModeByFilenameOrFirstLine(uri.fsPath, firstLineText);
|
||||
const model = this._modelService.createModel(value, mode, uri);
|
||||
|
||||
// if neither the extension host nor an editor reference this
|
||||
// document anymore we destroy the model to reclaim memory
|
||||
const handle = setInterval(() => {
|
||||
this._editorService.inputToType({ resource: uri }).then(input => {
|
||||
if (!this._editorService.isVisible(input, true)) {
|
||||
return this._proxy.$isDocumentReferenced(uri).then(referenced => {
|
||||
if (!referenced) {
|
||||
clearInterval(handle);
|
||||
this._modelService.destroyModel(uri);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, onUnexpectedError);
|
||||
}, 30 * 1000);
|
||||
|
||||
return model;
|
||||
|
||||
}).then(() => {
|
||||
return true;
|
||||
$registerTextContentProvider(scheme: string): void {
|
||||
this._resourceContentProvider[scheme] = ResourceEditorInput.registerResourceContentProvider(scheme, {
|
||||
provideTextContent: (uri: URI): TPromise<string> => {
|
||||
return this._proxy.$provideTextDocumentContent(uri);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$onVirtualDocumentChange(uri: URI, value: string): TPromise<any> {
|
||||
$unregisterTextContentProvider(scheme: string): void {
|
||||
const registration = this._resourceContentProvider[scheme];
|
||||
if (registration) {
|
||||
registration.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
$onVirtualDocumentChange(uri: URI, value: string): void {
|
||||
const model = this._modelService.getModel(uri);
|
||||
if (model) {
|
||||
model.setValue(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private _runDocumentCleanup(): void {
|
||||
this._proxy.$getUnferencedDocuments().then(resources => {
|
||||
|
||||
const toBeDisposed: URI[] = [];
|
||||
const promises = resources.map(resource => {
|
||||
return this._editorService.inputToType({ resource }).then(input => {
|
||||
if (!this._editorService.isVisible(input, true)) {
|
||||
toBeDisposed.push(resource);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return TPromise.join(promises).then(() => {
|
||||
for (let resource of toBeDisposed) {
|
||||
this._modelService.destroyModel(resource);
|
||||
}
|
||||
});
|
||||
|
||||
}, onUnexpectedError);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user