diff --git a/packages/monaco/src/browser/monaco-text-model-service.ts b/packages/monaco/src/browser/monaco-text-model-service.ts index 2ede3881a36f7..a9d2fb27abc0d 100644 --- a/packages/monaco/src/browser/monaco-text-model-service.ts +++ b/packages/monaco/src/browser/monaco-text-model-service.ts @@ -17,13 +17,20 @@ import { inject, injectable } from 'inversify'; import { MonacoToProtocolConverter, ProtocolToMonacoConverter } from 'monaco-languageclient'; import URI from '@theia/core/lib/common/uri'; -import { ResourceProvider, ReferenceCollection, Event } from '@theia/core'; +import { CommandRegistry, ResourceProvider, ReferenceCollection, Event } from '@theia/core'; import { EditorPreferences, EditorPreferenceChange } from '@theia/editor/lib/browser'; import { MonacoEditorModel } from './monaco-editor-model'; +import { MessageClient, MessageType } from '@theia/core/lib/common'; +import { FileSystem, FileStat } from '@theia/filesystem/lib/common/filesystem'; +import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; @injectable() export class MonacoTextModelService implements monaco.editor.ITextModelService { + @inject(FileSystem) protected readonly fileSystem: FileSystem; + @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(CommandRegistry) protected readonly commands: CommandRegistry; + protected readonly _models = new ReferenceCollection( uri => this.loadModel(new URI(uri)) ); @@ -40,6 +47,9 @@ export class MonacoTextModelService implements monaco.editor.ITextModelService { @inject(ProtocolToMonacoConverter) protected readonly p2m: ProtocolToMonacoConverter; + @inject(MessageClient) + protected readonly messages: MessageClient; + get models(): MonacoEditorModel[] { return this._models.values(); } @@ -57,14 +67,48 @@ export class MonacoTextModelService implements monaco.editor.ITextModelService { } protected async loadModel(uri: URI): Promise { - await this.editorPreferences.ready; - const resource = await this.resourceProvider(uri); - const model = await (new MonacoEditorModel(resource, this.m2p, this.p2m, { encoding: this.editorPreferences.get('files.encoding') }).load()); - this.updateModel(model); - model.textEditorModel.onDidChangeLanguage(() => this.updateModel(model)); - const disposable = this.editorPreferences.onPreferenceChanged(change => this.updateModel(model, change)); - model.onDispose(() => disposable.dispose()); - return model; + try { + await this.editorPreferences.ready; + const resource = await this.resourceProvider(uri); + const model = await (new MonacoEditorModel(resource, this.m2p, this.p2m, { encoding: this.editorPreferences.get('files.encoding') }).load()); + this.updateModel(model); + model.textEditorModel.onDidChangeLanguage(() => this.updateModel(model)); + const disposable = this.editorPreferences.onPreferenceChanged(change => this.updateModel(model, change)); + model.onDispose(() => disposable.dispose()); + return model; + } catch (error) { + const msg = 'Unable to open "' + uri + '": ' + error; + this.messages.showMessage({ type: MessageType.Error, text: msg, actions: ['CREATE'] }) + .then(res => { + if (res === 'CREATE') { + this.getOrCreateDirectory(uri.parent).then(parent => { + if (parent) { + const parentUri = new URI(parent.uri); + const name = uri.path.name; + const ext = uri.path.ext; + const fileUri = parentUri.resolve(name) + + (ext && ext !== null ? '.' && ext : ''); + + this.fileSystem.createFile(fileUri.toString()).then(() => { + this.commands.executeCommand('vscode.open', fileUri); + }); + } + }); + } + }); + return Promise.reject(error); + } + } + + protected async getOrCreateDirectory(uri: URI): Promise { + const stat = await this.fileSystem.getFileStat(uri.toString()); + if (stat) { + if (stat.isDirectory) { + return stat; + } + return this.getOrCreateDirectory(uri.parent); + } + return this.fileSystem.createFolder(uri.toString()); } protected readonly modelOptions: { diff --git a/packages/plugin-ext-vscode/src/browser/plugin-vscode-commands-contribution.ts b/packages/plugin-ext-vscode/src/browser/plugin-vscode-commands-contribution.ts index 94661977e454e..e6a9d4e86cc07 100644 --- a/packages/plugin-ext-vscode/src/browser/plugin-vscode-commands-contribution.ts +++ b/packages/plugin-ext-vscode/src/browser/plugin-vscode-commands-contribution.ts @@ -76,6 +76,8 @@ export class PluginVscodeCommandsContribution implements CommandContribution { if (!resource) { throw new Error(`${VscodeCommands.OPEN.id} command requires at least URI argument.`); } + + resource = URI.parse(resource.toString()); if (!URI.isUri(resource)) { throw new Error(`Invalid argument for ${VscodeCommands.OPEN.id} command with URI argument. Found ${resource}`); }