Skip to content

Commit

Permalink
Read snippets as plugin resources
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Mäder <[email protected]>
  • Loading branch information
tsmaeder committed Sep 3, 2020
1 parent e198c7c commit 03dbe0d
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 24 deletions.
17 changes: 10 additions & 7 deletions packages/monaco/src/browser/monaco-snippet-suggest-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ import * as jsoncparser from 'jsonc-parser';
import { injectable, inject } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { FileOperationError } from '@theia/filesystem/lib/common/files';
import { ResourceProvider } from '@theia/core/lib/common';

@injectable()
export class MonacoSnippetSuggestProvider implements monaco.languages.CompletionItemProvider {

private static readonly _maxPrefix = 10000;

@inject(FileService)
protected readonly fileService: FileService;
@inject(ResourceProvider)
protected readonly resourceProvider: ResourceProvider;

protected readonly snippets = new Map<string, Snippet[]>();
protected readonly pendingSnippets = new Map<string, Promise<void>[]>();
Expand Down Expand Up @@ -114,7 +114,7 @@ export class MonacoSnippetSuggestProvider implements monaco.languages.Completion
}
}

fromURI(uri: string | URI, options: SnippetLoadOptions): Disposable {
fromURI(uri: string, options: SnippetLoadOptions): Disposable {
const toDispose = new DisposableCollection(Disposable.create(() => { /* mark as not disposed */ }));
const pending = this.loadURI(uri, options, toDispose);
const { language } = options;
Expand All @@ -136,10 +136,11 @@ export class MonacoSnippetSuggestProvider implements monaco.languages.Completion
/**
* should NOT throw to prevent load errors on suggest
*/
protected async loadURI(uri: string | URI, options: SnippetLoadOptions, toDispose: DisposableCollection): Promise<void> {
protected async loadURI(uri: string, options: SnippetLoadOptions, toDispose: DisposableCollection): Promise<void> {
const resourceUri = new URI(uri);
const resource = await this.resourceProvider(resourceUri);
try {
const resource = typeof uri === 'string' ? new URI(uri) : uri;
const { value } = await this.fileService.read(resource);
const value = await resource.readContents();
if (toDispose.disposed) {
return;
}
Expand All @@ -149,6 +150,8 @@ export class MonacoSnippetSuggestProvider implements monaco.languages.Completion
if (!(e instanceof FileOperationError)) {
console.error(e);
}
} finally {
resource.dispose();
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/plugin-ext-vscode/src/node/scanner-vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
entryPoint: {
backend: plugin.main
},
iconUrl: plugin.icon && PluginPackage.toPluginUrl(plugin, plugin.icon),
readmeUrl: PluginPackage.toPluginUrl(plugin, './README.md'),
licenseUrl: PluginPackage.toPluginUrl(plugin, './LICENSE')
iconUrl: plugin.icon && PluginPackage.toPluginUri(plugin, plugin.icon),
readmeUrl: PluginPackage.toPluginUri(plugin, './README.md'),
licenseUrl: PluginPackage.toPluginUri(plugin, './LICENSE')
};
return result;
}
Expand Down
20 changes: 18 additions & 2 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,24 @@ export interface PluginPackage {
icon?: string;
}
export namespace PluginPackage {
export function toPluginUrl(pck: PluginPackage, relativePath: string): string {
return `hostedPlugin/${getPluginId(pck)}/${encodeURIComponent(relativePath)}`;
export const RESOURCE_SCHEME = 'pluginresource';

export function toPluginUri(pck: PluginPackage, relativePath: string): string {
return PluginUri.toPluginUri(getPluginId(pck), relativePath);
}

export function toPlugingUriPath(pck: PluginPackage, relativePath: string): string {
return PluginUri.toPlugingUriPath(getPluginId(pck), relativePath);
}
}

export namespace PluginUri {
export function toPlugingUriPath(pluginId: string, relativePath: string): string {
return `/hostedPlugin/${pluginId}/${encodeURIComponent(relativePath)}`;
}

export function toPluginUri(pluginId: string, relativePath: string): string {
return `${PluginPackage.RESOURCE_SCHEME}://${toPlugingUriPath(pluginId, relativePath)}`;
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-ext/src/hosted/browser/worker/worker-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { RPCProtocolImpl } from '../../../common/rpc-protocol';
import { PluginManagerExtImpl } from '../../../plugin/plugin-manager';
import { MAIN_RPC_CONTEXT, Plugin, emptyPlugin } from '../../../common/plugin-api-rpc';
import { createAPIFactory } from '../../../plugin/plugin-context';
import { getPluginId, PluginMetadata, PluginPackage } from '../../../common/plugin-protocol';
import { PluginMetadata, PluginPackage } from '../../../common/plugin-protocol';
import * as theia from '@theia/plugin';
import { PreferenceRegistryExtImpl } from '../../../plugin/preference-registry';
import { ExtPluginApi } from '../../../common/plugin-ext-api-contribution';
Expand Down Expand Up @@ -69,7 +69,7 @@ const pluginManager = new PluginManagerExtImpl({
if (isElectron()) {
ctx.importScripts(plugin.pluginPath);
} else {
ctx.importScripts('/hostedPlugin/' + getPluginId(plugin.model) + '/' + plugin.pluginPath);
ctx.importScripts(PluginPackage.toPlugingUriPath(plugin.rawModel, plugin.pluginPath));
}
}

Expand Down
8 changes: 6 additions & 2 deletions packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export class TheiaPluginScanner implements PluginScanner {
}

protected toPluginUrl(pck: PluginPackage, relativePath: string): string {
return PluginPackage.toPluginUrl(pck, relativePath);
return PluginPackage.toPluginUri(pck, relativePath);
}

protected readColors(pck: PluginPackage): ColorDefinition[] | undefined {
Expand Down Expand Up @@ -418,10 +418,14 @@ export class TheiaPluginScanner implements PluginScanner {
const result: SnippetContribution[] = [];
for (const contribution of pck.contributes.snippets) {
if (contribution.path) {
const absolutePath = path.join(pck.packagePath, contribution.path);
const normalizedPath = path.normalize(absolutePath);
const relativePath = path.relative(pck.packagePath, normalizedPath);

result.push({
language: contribution.language,
source: pck.displayName || pck.name,
uri: FileUri.create(path.join(pck.packagePath, contribution.path)).toString()
uri: PluginPackage.toPluginUri(pck, relativePath).toString()
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { WebviewResourceCache } from './webview/webview-resource-cache';
import { PluginIconThemeService, PluginIconThemeFactory, PluginIconThemeDefinition, PluginIconTheme } from './plugin-icon-theme-service';
import { PluginTreeViewNodeLabelProvider } from './view/plugin-tree-view-node-label-provider';
import { WebviewWidgetFactory } from './webview/webview-widget-factory';
import { PluginResourceResolver } from './plugin-resource';

export default new ContainerModule((bind, unbind, isBound, rebind) => {

Expand Down Expand Up @@ -96,6 +97,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(UntitledResourceResolver).toSelf().inSingletonScope();
bind(ResourceResolver).toService(UntitledResourceResolver);

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

bind(FrontendApplicationContribution).toDynamicValue(ctx => ({
onStart(): MaybePromise<void> {
ctx.container.get(HostedPluginSupport).onStart(ctx.container);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import debounce = require('lodash.debounce');
import * as jsoncparser from 'jsonc-parser';
import { injectable, inject, postConstruct } from 'inversify';
import { IconThemeService, IconTheme, IconThemeDefinition } from '@theia/core/lib/browser/icon-theme-service';
import { IconThemeContribution, DeployedPlugin, UiTheme, getPluginId } from '../../common/plugin-protocol';
import { IconThemeContribution, DeployedPlugin, UiTheme, getPluginId, PluginUri } from '../../common/plugin-protocol';
import URI from '@theia/core/lib/common/uri';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { Emitter } from '@theia/core/lib/common/event';
Expand Down Expand Up @@ -331,7 +331,7 @@ export class PluginIconTheme extends PluginIconThemeDefinition implements IconTh
const iconUri = this.locationUri.resolve(iconPath);
const relativePath = this.packageRootUri.path.relative(iconUri.path.normalize());
return relativePath && `url('${new Endpoint({
path: `hostedPlugin/${this.pluginId}/${encodeURIComponent(relativePath.normalize().toString())}`
path: PluginUri.toPlugingUriPath(this.pluginId, relativePath.toString())
}).getRestUrl().toString()}')`;
}

Expand Down
73 changes: 73 additions & 0 deletions packages/plugin-ext/src/main/browser/plugin-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/********************************************************************************
* Copyright (C) 2019 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { Resource, ResourceReadOptions, ResourceResolver, MaybePromise } from '@theia/core/lib/common';
import { Endpoint } from '@theia/core/lib/browser';
import URI from '@theia/core/lib/common/uri';
import { PluginPackage } from '../../common';
import { injectable } from 'inversify';

export class PluginResource implements Resource {
readonly uri: URI;

constructor(pluginId: string, relativePath: string) {
this.uri = PluginResource.getUri(pluginId, relativePath);
}

private static getUri(pluginId: string, relativePath: string): URI {
return new Endpoint({
path: `hostedPlugin/${pluginId}/${encodeURIComponent(relativePath.normalize().toString())}`
}).getRestUrl();
}

async readContents(options?: ResourceReadOptions): Promise<string> {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();

request.onreadystatechange = function (): void {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('Could not fetch plugin resource'));
}
}
};

request.open('GET', this.uri.toString(), true);
request.send();
});
}

dispose(): void {

}
}

@injectable()
export class PluginResourceResolver implements ResourceResolver {
resolve(uri: URI): MaybePromise<Resource> {
if (uri.scheme !== PluginPackage.RESOURCE_SCHEME) {
throw new Error('Not a plugin resource');
}
const pathAsString = uri.path.toString();
const matches = new RegExp('/hostedPlugin/(.*)/(.*)').exec(pathAsString);
if (!matches) {
throw new Error('path does not match: ' + uri.toString());
}
return new PluginResource(matches[1], matches[2]);
}
}
8 changes: 5 additions & 3 deletions packages/plugin-ext/src/main/browser/plugin-shared-style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
import { injectable } from 'inversify';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { ThemeService, Theme } from '@theia/core/lib/browser/theming';
import { IconUrl } from '../../common/plugin-protocol';
import { IconUrl, PluginPackage } from '../../common/plugin-protocol';
import { Reference, SyncReferenceCollection } from '@theia/core/lib/common/reference';
import { Endpoint } from '@theia/core/lib/browser/endpoint';
import URI from '@theia/core/lib/common/uri';

export interface PluginIconKey {
url: IconUrl
Expand Down Expand Up @@ -121,8 +122,9 @@ export class PluginSharedStyle {
}

static toExternalIconUrl(iconUrl: string): string {
if (iconUrl.startsWith('hostedPlugin/')) {
return new Endpoint({ path: iconUrl }).getRestUrl().toString();
const uri = new URI(iconUrl);
if (PluginPackage.RESOURCE_SCHEME === uri.scheme) {
return new Endpoint({ path: uri.path.toString() }).getRestUrl().toString();
}
return iconUrl;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-ext/src/plugin/plugin-icon-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ export namespace PluginIconPath {
const absolutePath = path.isAbsolute(arg) ? arg : path.join(packagePath, arg);
const normalizedPath = path.normalize(absolutePath);
const relativePath = path.relative(packagePath, normalizedPath);
return PluginPackage.toPluginUrl(plugin.rawModel, relativePath);
return PluginPackage.toPluginUri(plugin.rawModel, relativePath);
}
}
2 changes: 1 addition & 1 deletion packages/plugin-ext/src/plugin/quick-open.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ export class QuickInputExt implements QuickInput {
const absolutePath = path.isAbsolute(arg) ? arg : path.join(packagePath, arg);
const normalizedPath = path.normalize(absolutePath);
const relativePath = path.relative(packagePath, normalizedPath);
return PluginPackage.toPluginUrl(this.plugin.rawModel, relativePath);
return PluginPackage.toPluginUri(this.plugin.rawModel, relativePath);
};
if ('id' in iconPath || iconPath instanceof ThemeIcon) {
return iconPath;
Expand Down
3 changes: 2 additions & 1 deletion packages/vsx-registry/src/browser/vsx-extension.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Endpoint } from '@theia/core/lib/browser/endpoint';
import { VSXEnvironment } from '../common/vsx-environment';
import { VSXExtensionsSearchModel } from './vsx-extensions-search-model';
import { VSXExtensionNamespaceAccess, VSXUser } from '../common/vsx-registry-types';
import { PluginSharedStyle } from '@theia/plugin-ext/lib/main/browser/plugin-shared-style';

@injectable()
export class VSXExtensionData {
Expand Down Expand Up @@ -147,7 +148,7 @@ export class VSXExtension implements VSXExtensionData, TreeElement {
const plugin = this.plugin;
const iconUrl = plugin && plugin.metadata.model.iconUrl;
if (iconUrl) {
return new Endpoint({ path: iconUrl }).getRestUrl().toString();
return PluginSharedStyle.toExternalIconUrl(iconUrl);
}
return this.data['iconUrl'];
}
Expand Down

0 comments on commit 03dbe0d

Please sign in to comment.