Skip to content

Commit

Permalink
Add editor life cycle methods: open, save and close (#31)
Browse files Browse the repository at this point in the history
eclipse-che/che#9435 add editor life cycle methods: open, save and close

Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
  • Loading branch information
evidolob authored Jun 18, 2018
1 parent 5da1c6e commit f2cc293
Show file tree
Hide file tree
Showing 10 changed files with 979 additions and 726 deletions.
34 changes: 20 additions & 14 deletions packages/plugin-ext/src/common/editor-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// enum copied from monaco.d.ts
/**
* The style in which the editor's cursor should be rendered.
*/
Expand Down Expand Up @@ -41,19 +46,20 @@ export enum TextEditorCursorStyle {
}

export function cursorStyleToString(cursorStyle: TextEditorCursorStyle): string {
if (cursorStyle === TextEditorCursorStyle.Line) {
return 'line';
} else if (cursorStyle === TextEditorCursorStyle.Block) {
return 'block';
} else if (cursorStyle === TextEditorCursorStyle.Underline) {
return 'underline';
} else if (cursorStyle === TextEditorCursorStyle.LineThin) {
return 'line-thin';
} else if (cursorStyle === TextEditorCursorStyle.BlockOutline) {
return 'block-outline';
} else if (cursorStyle === TextEditorCursorStyle.UnderlineThin) {
return 'underline-thin';
} else {
throw new Error('cursorStyleToString: Unknown cursorStyle');
switch (cursorStyle) {
case TextEditorCursorStyle.Line:
return 'line';
case TextEditorCursorStyle.Block:
return 'block';
case TextEditorCursorStyle.Underline:
return 'underline';
case TextEditorCursorStyle.LineThin:
return 'line-thin';
case TextEditorCursorStyle.BlockOutline:
return 'block-outline';
case TextEditorCursorStyle.UnderlineThin:
return 'underline-thin';
default:
throw new Error('cursorStyleToString: Unknown cursorStyle');
}
}
7 changes: 7 additions & 0 deletions packages/plugin-ext/src/common/uri-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,11 @@ export interface UriComponents {
path: string;
query: string;
fragment: string;
external?: string;
}

// some well known URI schemas
export namespace Schemes {
export const File = 'file';
export const Untitled = 'untitled';
}
28 changes: 23 additions & 5 deletions packages/plugin-ext/src/main/browser/documents-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { DisposableCollection, Disposable } from "@theia/core";
import { MonacoEditorModel } from "@theia/monaco/lib/browser/monaco-editor-model";
import { RPCProtocol } from "../../api/rpc-protocol";
import { EditorModelService } from "./text-editor-model-service";
import { createUntitledResource } from "./editor/untitled-resource";
import { EditorManager } from "@theia/editor/lib/browser";
import URI from "@theia/core/lib/common/uri";
import { Saveable } from "@theia/core/lib/browser";

export class DocumentsMainImpl implements DocumentsMain {
private proxy: DocumentsExt;
Expand All @@ -21,7 +25,8 @@ export class DocumentsMainImpl implements DocumentsMain {
constructor(
editorsAndDocuments: EditorsAndDocumentsMain,
modelService: EditorModelService,
rpc: RPCProtocol
rpc: RPCProtocol,
private editorManger: EditorManager
) {
this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.DOCUMENTS_EXT);

Expand Down Expand Up @@ -82,13 +87,26 @@ export class DocumentsMainImpl implements DocumentsMain {
this.modelToDispose.delete(modelUrl);
}

$tryCreateDocument(options?: { language?: string | undefined; content?: string | undefined; } | undefined): Promise<UriComponents> {
throw new Error("Method not implemented.");
$tryCreateDocument(options?: { language?: string; content?: string; }): Promise<UriComponents> {
let language;
let content;
if (options) {
language = options.language;
content = options.content;
}
return Promise.resolve(createUntitledResource(content, language));
}

$tryOpenDocument(uri: UriComponents): Promise<void> {
throw new Error("Method not implemented.");
return this.editorManger.open(new URI(uri.external!)).then(() => void 0);
}

$trySaveDocument(uri: UriComponents): Promise<boolean> {
throw new Error("Method not implemented.");
return this.editorManger.getByUri(new URI(uri.external!)).then(e => {
if (e) {
return Saveable.save(e).then(() => true);
}
return Promise.resolve(false);
});
}
}
55 changes: 55 additions & 0 deletions packages/plugin-ext/src/main/browser/editor/untitled-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { ResourceResolver, Resource } from "@theia/core";
import URI from "@theia/core/lib/common/uri";
import { injectable } from "inversify";
import { Schemes } from "../../../common/uri-components";
import { UriComponents } from "../../../common/uri-components";

const resources = new Map<string, UntitledResource>();
let index = 0;
@injectable()
export class UntitledResourceResolver implements ResourceResolver {
resolve(uri: URI): Resource | Promise<Resource> {
if (uri.scheme === Schemes.Untitled) {
return resources.get(uri.toString())!;
}
throw new Error(`scheme ${uri.scheme} is not '${Schemes.Untitled}'`);
}
}

export class UntitledResource implements Resource {

constructor(public uri: URI, private content?: string) {
resources.set(this.uri.toString(), this);
}

readContents(options?: { encoding?: string | undefined; } | undefined): Promise<string> {
return Promise.resolve(this.content ? this.content : '');
}

dispose(): void {
resources.delete(this.uri.toString());
}
}

export function createUntitledResource(content?: string, language?: string): UriComponents {
let extension;
if (language) {
for (const lang of monaco.languages.getLanguages()) {
if (lang.id === language) {
if (lang.extensions) {
extension = lang.extensions[0];
break;
}
}
}
}
const resource = new UntitledResource(new URI().withScheme(Schemes.Untitled).withPath(`/Untitled-${index++}${extension ? extension : ''}`), content);
return monaco.Uri.parse(resource.uri.toString());
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Emitter, Event } from '@theia/core';
import { DisposableCollection } from "@theia/core";
import { DocumentsMainImpl } from './documents-main';
import { TextEditorsMainImpl } from './text-editors-main';
import { EditorManager } from '@theia/editor/lib/browser';

export class EditorsAndDocumentsMain {
private toDispose = new DisposableCollection();
Expand All @@ -40,8 +41,9 @@ export class EditorsAndDocumentsMain {

const editorService = container.get<TextEditorService>(TextEditorService);
const modelService = container.get<EditorModelService>(EditorModelService);
const editorManager = container.get<EditorManager>(EditorManager);

const documentsMain = new DocumentsMainImpl(this, modelService, rpc);
const documentsMain = new DocumentsMainImpl(this, modelService, rpc, editorManager);
rpc.set(PLUGIN_RPC_CONTEXT.DOCUMENTS_MAIN, documentsMain);

const editorsMain = new TextEditorsMainImpl(this, rpc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import '../../../src/main/style/status-bar.css';

import { ContainerModule } from "inversify";
import { FrontendApplicationContribution, FrontendApplication, WidgetFactory, KeybindingContribution } from "@theia/core/lib/browser";
import { MaybePromise, CommandContribution, MenuContribution } from "@theia/core/lib/common";
import { MaybePromise, CommandContribution, MenuContribution, ResourceResolver } from "@theia/core/lib/common";
import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging';
import { PluginWorker } from './plugin-worker';
import { HostedPluginSupport } from "../../hosted/browser/hosted-plugin";
Expand All @@ -29,6 +29,7 @@ import '../../../src/main/browser/style/index.css';
import { PluginExtDeployCommandService } from "./plugin-ext-deploy-command";
import { TextEditorService, TextEditorServiceImpl } from './text-editor-service';
import { EditorModelService, EditorModelServiceImpl } from './text-editor-model-service';
import { UntitledResourceResolver } from './editor/untitled-resource';

export default new ContainerModule(bind => {
bind(ModalNotification).toSelf().inSingletonScope();
Expand All @@ -48,6 +49,9 @@ export default new ContainerModule(bind => {
bind(TextEditorService).to(TextEditorServiceImpl).inSingletonScope();
bind(EditorModelService).to(EditorModelServiceImpl).inSingletonScope();

bind(UntitledResourceResolver).toSelf().inSingletonScope();
bind(ResourceResolver).toService(UntitledResourceResolver);

bind(FrontendApplicationContribution).toDynamicValue(ctx => ({
onStart(app: FrontendApplication): MaybePromise<void> {
const worker = ctx.container.get(PluginWorker);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export class PluginApiFrontendContribution implements CommandContribution {
commands.registerCommand(PluginExtDeployCommandService.COMMAND, {
execute: () => this.pluginExtDeployCommandService.deploy()
});

// this command only for compatibility reason
commands.registerCommand({ id: 'workbench.action.closeActiveEditor' }, {
execute: () => commands.executeCommand('core.close.tab')
});
}

}
45 changes: 42 additions & 3 deletions packages/plugin-ext/src/plugin/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
import { DocumentsExt, ModelChangedEvent } from "../api/plugin-api";
import { DocumentsExt, ModelChangedEvent, PLUGIN_RPC_CONTEXT, DocumentsMain } from "../api/plugin-api";
import URI from "vscode-uri";
import { UriComponents } from '../common/uri-components';
import { RPCProtocol } from "../api/rpc-protocol";
Expand All @@ -27,10 +27,11 @@ export class DocumentsExtImpl implements DocumentsExt {
readonly onDidChangeDocument: Event<theia.TextDocumentChangeEvent> = this._onDidChangeDocument.event;
readonly onDidSaveDocument: Event<theia.TextDocument> = this._onDidSaveDocument.event;

// private proxy: DocumentsMain;
private proxy: DocumentsMain;
private documentLoader = new Map<string, Promise<DocumentDataExt | undefined>>();

constructor(rpc: RPCProtocol, private editorsAndDocuments: EditorsAndDocumentsExtImpl) {
// this.proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.DOCUMENTS_MAIN);
this.proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.DOCUMENTS_MAIN);
this.toDispose.push(
this.editorsAndDocuments.onDidAddDocuments(documents => {
for (const document of documents) {
Expand Down Expand Up @@ -101,4 +102,42 @@ export class DocumentsExtImpl implements DocumentsExt {
getAllDocumentData(): DocumentDataExt[] {
return this.editorsAndDocuments.allDocuments();
}

getDocumentData(resource: theia.Uri): DocumentDataExt | undefined {
if (!resource) {
return undefined;
}
const data = this.editorsAndDocuments.getDocument(resource.toString());
if (data) {
return data;
}
return undefined;
}

ensureDocumentData(uri: URI): Promise<DocumentDataExt | undefined> {

const cached = this.editorsAndDocuments.getDocument(uri.toString());
if (cached) {
return Promise.resolve(cached);
}

let promise = this.documentLoader.get(uri.toString());
if (!promise) {
promise = this.proxy.$tryOpenDocument(uri).then(() => {
this.documentLoader.delete(uri.toString());
return this.editorsAndDocuments.getDocument(uri.toString());
}, err => {
this.documentLoader.delete(uri.toString());
return Promise.reject(err);
});
this.documentLoader.set(uri.toString(), promise);
}

return promise;
}

createDocumentData(options?: { language?: string; content?: string }): Promise<URI> {
return this.proxy.$tryCreateDocument(options).then(data => URI.revive(data));
}

}
21 changes: 21 additions & 0 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { DocumentsExtImpl } from './documents';
import Uri from 'vscode-uri';
import { TextEditorCursorStyle } from '../common/editor-options';
import { PreferenceRegistryExtImpl } from './preference-registry';
import URI from 'vscode-uri';

export function createAPI(rpc: RPCProtocol): typeof theia {
const commandRegistryExt = rpc.set(MAIN_RPC_CONTEXT.COMMAND_REGISTRY_EXT, new CommandRegistryImpl(rpc));
Expand Down Expand Up @@ -163,6 +164,26 @@ export function createAPI(rpc: RPCProtocol): typeof theia {
},
onDidChangeConfiguration(listener, thisArgs?, disposables?): theia.Disposable {
return preferenceRegistryExt.onDidChangeConfiguration(listener, thisArgs, disposables);
},
openTextDocument(uriOrFileNameOrOptions?: theia.Uri | string | { language?: string; content?: string; }) {
let uriPromise: Promise<URI>;

const options = uriOrFileNameOrOptions as { language?: string; content?: string; };
if (typeof uriOrFileNameOrOptions === 'string') {
uriPromise = Promise.resolve(URI.file(uriOrFileNameOrOptions));
} else if (uriOrFileNameOrOptions instanceof URI) {
uriPromise = Promise.resolve(uriOrFileNameOrOptions);
} else if (!options || typeof options === 'object') {
uriPromise = documents.createDocumentData(options);
} else {
throw new Error('illegal argument - uriOrFileNameOrOptions');
}

return uriPromise.then(uri =>
documents.ensureDocumentData(uri).then(() => {
const data = documents.getDocumentData(uri);
return data && data.document;
}));
}
};

Expand Down
Loading

0 comments on commit f2cc293

Please sign in to comment.