Skip to content

Commit

Permalink
Fixes TypeFox/Theia#54: LanguageClientContribution
Browse files Browse the repository at this point in the history
  • Loading branch information
akosyakov committed May 6, 2017
1 parent 7375d3c commit fc426d9
Show file tree
Hide file tree
Showing 30 changed files with 650 additions and 165 deletions.
7 changes: 6 additions & 1 deletion examples/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ import "theia/src/navigator/browser/style/index.css";
import "theia/src/terminal/browser/terminal.css";

// terminal extension
import terminalFrontendModule from 'theia/lib/terminal/browser/terminal-frontend-module'
import terminalFrontendModule from 'theia/lib/terminal/browser/terminal-frontend-module';
import "xterm/dist/xterm.css";

// java extension
import { browserJavaModule } from 'theia/lib/java/browser/browser-java-module';
import 'theia/lib/java/browser/monaco-contribution';

export function start(clientContainer?: Container) {

// Create the common client container.
Expand All @@ -33,6 +37,7 @@ export function start(clientContainer?: Container) {
container.load(editorModule);
container.load(browserLanguagesModule);
container.load(monacoModule);
container.load(browserJavaModule);

// terminal extension
container.load(terminalFrontendModule);
Expand Down
9 changes: 7 additions & 2 deletions src/application/browser/application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { SelectionService } from '../common/selection-service'
import { CommonCommandContribution, CommonMenuContribution } from '../common/commands-common'
import { TheiaApplication } from './application'
import { OpenerService } from "./opener-service"
import { ResourceService } from "../common";
import { ResourceProvider, DefaultResourceProvider } from "../common";
import { CommandContribution, CommandContributionProvider, CommandRegistry } from "../common/command"
import { MenuModelRegistry, MenuContribution, MenuContributionProvider } from "../common/menu"
import {
Expand All @@ -21,7 +21,12 @@ import {
export const browserApplicationModule = new ContainerModule(bind => {
bind(TheiaApplication).toSelf().inSingletonScope()
bind(OpenerService).toSelf().inSingletonScope()
bind(ResourceService).toSelf().inSingletonScope();

bind(DefaultResourceProvider).toSelf().inSingletonScope();
bind(ResourceProvider).toProvider(context =>
uri => context.container.get(DefaultResourceProvider).get(uri)
);

bind(SelectionService).toSelf().inSingletonScope();
bind(CommandRegistry).toSelf().inSingletonScope()
bind(CommandContribution).to(CommonCommandContribution)
Expand Down
32 changes: 19 additions & 13 deletions src/application/common/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { injectable, multiInject } from "inversify";
import { injectable, multiInject, optional } from "inversify";
import URI from "../common/uri";

export interface Resource {
Expand All @@ -14,36 +14,42 @@ export interface Resource {
saveContents?(content: string, options?: { encoding?: string }): Promise<void>;
}

export const ResourceProvider = Symbol('ResourceProvider');
export interface ResourceProvider {
export const ResourceResolver = Symbol('ResourceResolver');
export interface ResourceResolver {
/**
* Reject if a resource cannot be provided.
*/
get(uri: URI): Promise<Resource>;
resolve(uri: URI): Promise<Resource>;
}

export const ResourceProvider = Symbol('ResourceProvider');
export type ResourceProvider = (uri: URI) => Promise<Resource>;

@injectable()
export class ResourceService {
export class DefaultResourceProvider {

constructor(
@multiInject(ResourceProvider) protected readonly providers: ResourceProvider[]
@multiInject(ResourceResolver) @optional()
protected readonly resolvers: ResourceResolver[] | undefined
) { }

/**
* Reject if a resource cannot be provided.
*/
get(uri: URI): Promise<Resource> {
if (this.providers.length === 0) {
return Promise.reject(this.createHandlerNotRegisteredError(uri));
if (!this.resolvers) {
return Promise.reject(this.createNotRegisteredError(uri));
}
const initial = this.providers[0].get(uri);
return this.providers.slice(1).reduce((current, provider) =>
current.catch(() => provider.get(uri)),
const initial = this.resolvers[0].resolve(uri);
return this.resolvers.slice(1).reduce((current, provider) =>
current.catch(() =>
provider.resolve(uri)
),
initial
).catch(reason => !!reason ? reason : this.createHandlerNotRegisteredError(uri));
).catch(reason => !!reason ? reason : this.createNotRegisteredError(uri));
}

protected createHandlerNotRegisteredError(uri: URI): any {
protected createNotRegisteredError(uri: URI): any {
return `A resource provider for '${uri.toString()}' is not registered.`;
}

Expand Down
3 changes: 2 additions & 1 deletion src/application/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
*/
export type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
};
export type MaybeArray<T> = T | T[];
14 changes: 7 additions & 7 deletions src/filesystem/browser/filesystem-client-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
*/

import { ContainerModule } from 'inversify';
import { CommandContribution, MenuContribution, ResourceProvider } from '../../application/common';
import { CommandContribution, MenuContribution, ResourceResolver } from '../../application/common';
import { WebSocketConnectionProvider } from '../../messaging/browser/connection';
import { FileSystem, FileSystemWatcher, FileResourceProvider } from "../common";
import { FileSystem, FileSystemWatcher, FileResourceResolver } from "../common";
import { FileCommandContribution, FileMenuContribution } from './filesystem-commands';

export const fileSystemClientModule = new ContainerModule(bind => {
Expand All @@ -17,12 +17,12 @@ export const fileSystemClientModule = new ContainerModule(bind => {
const connnection = ctx.container.get(WebSocketConnectionProvider);
const fileSystemClient = ctx.container.get(FileSystemWatcher).getFileSystemClient();
return connnection.createProxy<FileSystem>("/filesystem", fileSystemClient);
})
}).inSingletonScope();

bind(FileResourceProvider).toSelf().inSingletonScope();
bind(ResourceProvider).toDynamicValue(ctx => ctx.container.get(FileResourceProvider));
bind(FileResourceResolver).toSelf().inSingletonScope();
bind(ResourceResolver).toDynamicValue(ctx => ctx.container.get(FileResourceResolver));

bind<CommandContribution>(CommandContribution).to(FileCommandContribution);
bind<MenuContribution>(MenuContribution).to(FileMenuContribution);
bind<CommandContribution>(CommandContribution).to(FileCommandContribution).inSingletonScope();
bind<MenuContribution>(MenuContribution).to(FileMenuContribution).inSingletonScope();
});

6 changes: 3 additions & 3 deletions src/filesystem/common/file-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { injectable, inject } from "inversify";
import { Resource, ResourceProvider } from "../../application/common";
import { Resource, ResourceResolver } from "../../application/common";
import URI from "../../application/common/uri";
import { FileSystem, FileStat } from "./filesystem";

Expand Down Expand Up @@ -35,13 +35,13 @@ export class FileResource implements Resource {
}

@injectable()
export class FileResourceProvider implements ResourceProvider {
export class FileResourceResolver implements ResourceResolver {

constructor(
@inject(FileSystem) protected readonly fileSystem: FileSystem
) { }

get(uri: URI): Promise<Resource> {
resolve(uri: URI): Promise<FileResource> {
if (uri.scheme === 'file') {
return Promise.resolve(new FileResource(uri, this.fileSystem))
}
Expand Down
18 changes: 18 additions & 0 deletions src/java/browser/browser-java-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

/*
* Copyright (C) 2017 TypeFox 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 { ContainerModule } from "inversify";
import { ResourceResolver } from '../../application/common';
import { JavaClientContribution } from "./java-client-contribution";
import { LanguageClientContribution } from "../../languages/browser";

export const browserJavaModule = new ContainerModule(bind => {
bind(JavaClientContribution).toSelf().inSingletonScope();
bind(ResourceResolver).toDynamicValue(ctx => ctx.container.get(JavaClientContribution));
bind(LanguageClientContribution).toDynamicValue(ctx => ctx.container.get(JavaClientContribution));
});
12 changes: 12 additions & 0 deletions src/java/browser/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (C) 2017 TypeFox 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
*/

export * from '../common';
export * from './java-protocol';
export * from './java-resource';
export * from './java-client-contribution';
export * from './browser-java-module';
57 changes: 57 additions & 0 deletions src/java/browser/java-client-contribution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2017 TypeFox 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 { injectable } from "inversify";
import { ResourceResolver } from "../../application/common";
import URI from "../../application/common/uri";
import { ILanguageClient, LanguageIdentifier, LanguageClientContribution } from '../../languages/browser';
import { JAVA_LANGUAGE_ID } from '../common';
import { JavaResource } from "./java-resource";

@injectable()
export class JavaClientContribution implements ResourceResolver, LanguageClientContribution {

protected languageClient: ILanguageClient | undefined;

protected resolveDidStart: (languageClient: ILanguageClient) => void;
protected didStart: Promise<ILanguageClient>;

constructor() {
this.waitForDidStart();
}

resolve(uri: URI): Promise<JavaResource> {
const resolveLanguageClient = this.resolveLanguageClient.bind(this);
const javaResource = new JavaResource(uri, resolveLanguageClient);
return Promise.resolve(javaResource);
}

protected resolveLanguageClient(): Promise<ILanguageClient> {
return this.languageClient ? Promise.resolve(this.languageClient) : this.didStart;
}

onWillStart(language: LanguageIdentifier, languageClient: ILanguageClient): void {
if (language.description.id === JAVA_LANGUAGE_ID) {
languageClient.onReady().then(() =>
this.onDidStart(language, languageClient)
);
}
}

protected onDidStart(language: LanguageIdentifier, languageClient: ILanguageClient): void {
this.languageClient = languageClient
this.resolveDidStart(this.languageClient);
this.waitForDidStart();
}

protected waitForDidStart(): void {
this.didStart = new Promise<ILanguageClient>(resolve =>
this.resolveDidStart = resolve
);
}

}
13 changes: 13 additions & 0 deletions src/java/browser/java-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (C) 2017 TypeFox 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 { RequestType } from 'vscode-jsonrpc';
import { TextDocumentIdentifier } from "../../languages/common";

export namespace ClassFileContentsRequest {
export const type = new RequestType<TextDocumentIdentifier, string | undefined, void, void>('java/classFileContents');
}
29 changes: 29 additions & 0 deletions src/java/browser/java-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2017 TypeFox 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 { Resource } from "../../application/common";
import URI from "../../application/common/uri";
import { ILanguageClient } from "../../languages/browser";
import { ClassFileContentsRequest } from "./java-protocol";

export class JavaResource implements Resource {

constructor(
public uri: URI,
protected readonly resolveLanguageClient: () => Promise<ILanguageClient>
) { }

readContents(options: { encoding?: string }): Promise<string> {
const uri = this.uri.toString();
return this.resolveLanguageClient().then(languageClient =>
languageClient.sendRequest(ClassFileContentsRequest.type, { uri }).then(content =>
content || ''
)
);
}

}
21 changes: 21 additions & 0 deletions src/java/browser/monaco-contribution/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2017 TypeFox 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 { JAVA_LANGUAGE_ID } from '../../common';
import { configuration, monarchLanguage } from "./java-monaco-language";

monaco.languages.register({
id: JAVA_LANGUAGE_ID,
extensions: ['.java', '.jav', '.class'],
aliases: ['Java', 'java'],
mimetypes: ['text/x-java-source', 'text/x-java'],
});

monaco.languages.onLanguage(JAVA_LANGUAGE_ID, () => {
monaco.languages.setLanguageConfiguration(JAVA_LANGUAGE_ID, configuration);
monaco.languages.setMonarchTokensProvider(JAVA_LANGUAGE_ID, monarchLanguage);
});
Loading

0 comments on commit fc426d9

Please sign in to comment.