diff --git a/dev-packages/application-manager/src/expose-loader.ts b/dev-packages/application-manager/src/expose-loader.ts
index 43ecf4dfe50ec..3a23ce118ef9d 100644
--- a/dev-packages/application-manager/src/expose-loader.ts
+++ b/dev-packages/application-manager/src/expose-loader.ts
@@ -53,7 +53,7 @@ export = function (this: webpack.loader.LoaderContext, source: string, sourceMap
this.cacheable();
}
- let modulePackage = modulePackages.find(({ dir }) => this.resourcePath.startsWith(dir));
+ let modulePackage = modulePackages.find(({ dir }) => this.resourcePath.startsWith(dir + '/'));
if (modulePackage) {
this.callback(undefined, exposeModule(modulePackage, this.resourcePath, source), sourceMap);
return;
diff --git a/examples/api-tests/src/saveable.spec.js b/examples/api-tests/src/saveable.spec.js
index d67e294935f6c..4511c81e5c1c2 100644
--- a/examples/api-tests/src/saveable.spec.js
+++ b/examples/api-tests/src/saveable.spec.js
@@ -21,13 +21,12 @@ describe('Saveable', function () {
const { EditorManager } = require('@theia/editor/lib/browser/editor-manager');
const { EditorWidget } = require('@theia/editor/lib/browser/editor-widget');
- const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service');
+ const { PreferenceService } = require('@theia/core/lib/browser/preferences/preference-service');
const Uri = require('@theia/core/lib/common/uri');
const { Saveable, SaveableWidget } = require('@theia/core/lib/browser/saveable');
const { WorkspaceService } = require('@theia/workspace/lib/browser/workspace-service');
const { FileSystem } = require('@theia/filesystem/lib/common/filesystem');
const { MonacoEditor } = require('@theia/monaco/lib/browser/monaco-editor');
- const { DisposableCollection } = require('@theia/core/lib/common/disposable');
const { Deferred } = require('@theia/core/lib/common/promise-util');
/** @type {import('inversify').Container} */
@@ -79,9 +78,9 @@ describe('Saveable', function () {
assert.isTrue(Saveable.isDirty(widget), `should be dirty before '${edit}' save`);
await Saveable.save(widget);
assert.isFalse(Saveable.isDirty(widget), `should NOT be dirty after '${edit}' save`);
- assert.equal(editor.getControl().getValue(), edit, `model should be updated with '${edit}'`);
+ assert.equal(editor.getControl().getValue().trimRight(), edit, `model should be updated with '${edit}'`);
const state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, edit, `fs should be updated with '${edit}'`);
+ assert.equal(state.content.trimRight(), edit, `fs should be updated with '${edit}'`);
}
});
@@ -129,7 +128,7 @@ describe('Saveable', function () {
assert.isTrue(outOfSync, 'file should be out of sync');
assert.equal(outOfSyncCount, 1, 'user should be prompted only once with out of sync dialog');
assert.isTrue(Saveable.isDirty(widget), 'should be dirty after rejected save');
- assert.equal(editor.getControl().getValue(), longContent.substring(3), 'model should be updated');
+ assert.equal(editor.getControl().getValue().trimRight(), longContent.substring(3), 'model should be updated');
const state = await fileSystem.resolveContent(fileUri.toString());
assert.equal(state.content, 'baz', 'fs should NOT be updated');
});
@@ -151,7 +150,7 @@ describe('Saveable', function () {
await Saveable.save(widget);
assert.isTrue(outOfSync, 'file should be out of sync');
assert.isTrue(Saveable.isDirty(widget), 'should be dirty after rejected save');
- assert.equal(editor.getControl().getValue(), 'bar', 'model should be updated');
+ assert.equal(editor.getControl().getValue().trimRight(), 'bar', 'model should be updated');
let state = await fileSystem.resolveContent(fileUri.toString());
assert.equal(state.content, 'baz', 'fs should NOT be updated');
@@ -164,9 +163,9 @@ describe('Saveable', function () {
await Saveable.save(widget);
assert.isTrue(outOfSync, 'file should be out of sync');
assert.isFalse(Saveable.isDirty(widget), 'should NOT be dirty after save');
- assert.equal(editor.getControl().getValue(), 'bar', 'model should be updated');
+ assert.equal(editor.getControl().getValue().trimRight(), 'bar', 'model should be updated');
state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, 'bar', 'fs should be updated');
+ assert.equal(state.content.trimRight(), 'bar', 'fs should be updated');
});
it('accept new save', async () => {
@@ -181,9 +180,9 @@ describe('Saveable', function () {
await Saveable.save(widget);
assert.isTrue(outOfSync, 'file should be out of sync');
assert.isFalse(Saveable.isDirty(widget), 'should NOT be dirty after save');
- assert.equal(editor.getControl().getValue(), 'bar', 'model should be updated');
+ assert.equal(editor.getControl().getValue().trimRight(), 'bar', 'model should be updated');
const state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, 'bar', 'fs should be updated');
+ assert.equal(state.content.trimRight(), 'bar', 'fs should be updated');
});
it('cancel save on close', async () => {
@@ -243,7 +242,7 @@ describe('Saveable', function () {
assert.isTrue(outOfSync, 'file should be out of sync');
assert.isTrue(widget.isDisposed, 'model should be disposed after close');
const state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, 'bar', 'fs should be updated');
+ assert.equal(state.content.trimRight(), 'bar', 'fs should be updated');
});
it('normal close', async () => {
@@ -254,7 +253,7 @@ describe('Saveable', function () {
});
assert.isTrue(widget.isDisposed, 'model should be disposed after close');
const state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, 'bar', 'fs should be updated');
+ assert.equal(state.content.trimRight(), 'bar', 'fs should be updated');
});
it('delete file for saved', async () => {
@@ -320,7 +319,7 @@ describe('Saveable', function () {
assert.isFalse(Saveable.isDirty(widget), 'should NOT be dirty after save');
assert.isTrue(editor.document.valid, 'should be valid after save');
const state = await fileSystem.resolveContent(fileUri.toString());
- assert.equal(state.content, 'bar', 'fs should be updated');
+ assert.equal(state.content.trimRight(), 'bar', 'fs should be updated');
});
it('move file for saved', async function () {
diff --git a/examples/api-tests/src/typescript.spec.js b/examples/api-tests/src/typescript.spec.js
new file mode 100644
index 0000000000000..9a4a2e22db652
--- /dev/null
+++ b/examples/api-tests/src/typescript.spec.js
@@ -0,0 +1,556 @@
+/********************************************************************************
+ * Copyright (C) 2020 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
+ ********************************************************************************/
+
+// @ts-check
+///
+describe('TypeScript', function () {
+ this.timeout(15000);
+
+ const { assert } = chai;
+
+ const Uri = require('@theia/core/lib/common/uri');
+ const { DisposableCollection } = require('@theia/core/lib/common/disposable');
+ const { BrowserMainMenuFactory } = require('@theia/core/lib/browser/menu/browser-menu-plugin');
+ const { EditorManager } = require('@theia/editor/lib/browser/editor-manager');
+ const { EditorWidget } = require('@theia/editor/lib/browser/editor-widget');
+ const { EDITOR_CONTEXT_MENU } = require('@theia/editor/lib/browser/editor-menu');
+ const { WorkspaceService } = require('@theia/workspace/lib/browser/workspace-service');
+ const { MonacoEditor } = require('@theia/monaco/lib/browser/monaco-editor');
+ const { HostedPluginSupport } = require('@theia/plugin-ext/lib/hosted/browser/hosted-plugin');
+ const { ContextKeyService } = require('@theia/core/lib/browser/context-key-service');
+ const { CommandRegistry } = require('@theia/core/lib/common/command');
+ const { KeybindingRegistry } = require('@theia/core/lib/browser/keybinding');
+ const { OpenerService, open } = require('@theia/core/lib/browser/opener-service');
+ const { EditorPreviewWidget } = require('@theia/editor-preview/lib/browser/editor-preview-widget');
+ const { animationFrame } = require('@theia/core/lib/browser/browser');
+ const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service');
+
+ /** @type {import('inversify').Container} */
+ const container = window['theia'].container;
+ const editorManager = container.get(EditorManager);
+ const workspaceService = container.get(WorkspaceService);
+ const menuFactory = container.get(BrowserMainMenuFactory);
+ const pluginService = container.get(HostedPluginSupport);
+ const contextKeyService = container.get(ContextKeyService);
+ const commands = container.get(CommandRegistry);
+ const openerService = container.get(OpenerService);
+ const keybindings = container.get(KeybindingRegistry);
+ /** @type {import('@theia/core/lib/browser/preferences/preference-service').PreferenceService} */
+ const preferences = container.get(PreferenceService);
+
+ const rootUri = new Uri.default(workspaceService.tryGetRoots()[0].uri);
+ const serverUri = rootUri.resolve('src-gen/backend/server.js');
+ const inversifyUri = rootUri.resolve('../../node_modules/inversify/dts/inversify.d.ts').normalizePath();
+ const containerUri = rootUri.resolve('../../node_modules/inversify/dts/container/container.d.ts').normalizePath();
+
+ before(async function () {
+ await pluginService.load();
+ const plugin = pluginService.plugins.find(p => p.model.id === 'vscode.typescript-language-features');
+ await pluginService.activatePlugin(plugin.model.id);
+ });
+
+ beforeEach(async function () {
+ await editorManager.closeAll({ save: false });
+ });
+
+ /**
+ * @param {Uri.default} uri
+ * @param {boolean} preview
+ */
+ async function openEditor(uri, preview = false) {
+ const widget = await open(openerService, uri, { mode: 'activate', preview });
+ const editorWidget = widget instanceof EditorPreviewWidget ? widget.editorWidget : widget instanceof EditorWidget ? widget : undefined;
+ const editor = MonacoEditor.get(editorWidget);
+ // wait till tsserver is running, see:
+ // https://github.com/microsoft/vscode/blob/93cbbc5cae50e9f5f5046343c751b6d010468200/extensions/typescript-language-features/src/extension.ts#L98-L103
+ await new Promise(resolve => {
+ if (contextKeyService.match('typescript.isManagedFile')) {
+ resolve();
+ return;
+ }
+ contextKeyService.onDidChange(() => {
+ if (contextKeyService.match('typescript.isManagedFile')) {
+ resolve();
+ }
+ });
+ });
+ return editor;
+ }
+
+ /**
+ * @template T
+ * @param {() => Promise | T} condition
+ * @returns {Promise}
+ */
+ function waitForAnimation(condition) {
+ return new Promise(async (resolve, dispose) => {
+ toTearDown.push({ dispose });
+ do {
+ await animationFrame();
+ } while (!condition());
+ resolve();
+ });
+ }
+
+ /**
+ * We ignore attributes on purprse since they are not stable.
+ * But structure is important for us to see whether the plain text is rendered or markdown.
+ *
+ * @param {Element} element
+ * @returns {string}
+ */
+ function nodeAsString(element, indentation = '') {
+ const header = element.tagName;
+ let body = '';
+ const childIndentation = indentation + ' ';
+ for (const childNode of element.childNodes) {
+ if (childNode.nodeType === childNode.TEXT_NODE) {
+ body += childIndentation + `"${childNode.textContent}"` + '\n';
+ } else if (childNode instanceof HTMLElement) {
+ body += childIndentation + nodeAsString(childNode, childIndentation) + '\n';
+ }
+ }
+ const result = header + (body ? ' {\n' + body + indentation + '}' : '');
+ if (indentation) {
+ return result;
+ }
+ return `\n${result}\n`;
+ }
+
+ /**
+ * @param {MonacoEditor} editor
+ */
+ async function assertPeekOpened(editor) {
+ const referencesController = editor.getControl()._contributions['editor.contrib.referencesController'];
+ await waitForAnimation(() => referencesController._widget && referencesController._widget._tree.getFocus().length);
+
+ assert.isFalse(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(contextKeyService.match('referenceSearchVisible'));
+ assert.isTrue(contextKeyService.match('listFocus'));
+ }
+
+ /**
+ * @param {MonacoEditor} editor
+ */
+ async function openPeek(editor) {
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('referenceSearchVisible'));
+ assert.isFalse(contextKeyService.match('listFocus'));
+
+ await commands.executeCommand('editor.action.peekDefinition');
+ await assertPeekOpened(editor);
+ }
+
+ async function openReference() {
+ keybindings.dispatchKeyDown('Enter');
+ await waitForAnimation(() => contextKeyService.match('listFocus'));
+ assert.isFalse(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(contextKeyService.match('referenceSearchVisible'));
+ assert.isTrue(contextKeyService.match('listFocus'));
+ }
+
+ async function closePeek() {
+ keybindings.dispatchKeyDown('Escape');
+ await waitForAnimation(() => !contextKeyService.match('listFocus'));
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('referenceSearchVisible'));
+ assert.isFalse(contextKeyService.match('listFocus'));
+ }
+
+ afterEach(async () => {
+ await editorManager.closeAll({ save: false });
+ });
+
+ const toTearDown = new DisposableCollection();
+ afterEach(() => toTearDown.dispose());
+
+ it('document formating should be visible and enabled', async () => {
+ await openEditor(serverUri);
+ const menu = menuFactory.createContextMenu(EDITOR_CONTEXT_MENU);
+ const item = menu.items.find(i => i.command === 'editor.action.formatDocument');
+ assert.isDefined(item);
+ assert.isTrue(item.isVisible);
+ assert.isTrue(item.isEnabled);
+ });
+
+ describe('editor.action.revealDefinition', function () {
+ for (const preview of [false, true]) {
+ const from = 'an editor' + (preview ? ' preview' : '');
+ it('within ' + from, async function () {
+ const editor = await openEditor(serverUri, preview);
+ // con|tainer.load(backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 4 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+
+ await commands.executeCommand('editor.action.revealDefinition');
+
+ const activeEditor = MonacoEditor.get(editorManager.activeEditor);
+ assert.equal(editorManager.activeEditor.parent instanceof EditorPreviewWidget, preview);
+ assert.equal(activeEditor.uri.toString(), serverUri.toString());
+ // const |container = new Container();
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 11, column: 7 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'container');
+ });
+
+ it(`from ${from} to another editor`, async function () {
+ await editorManager.open(inversifyUri, { mode: 'open' });
+
+ const editor = await openEditor(serverUri, preview);
+ // const { Cont|ainer } = require('inversify');
+ editor.getControl().setPosition({ lineNumber: 5, column: 13 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'Container');
+
+ await commands.executeCommand('editor.action.revealDefinition');
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.isFalse(editorManager.activeEditor.parent instanceof EditorPreviewWidget);
+ assert.equal(activeEditor.uri.toString(), inversifyUri.toString());
+ // export { |Container } from "./container/container";
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 3, column: 10 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+ });
+
+ it(`from ${from} to an editor preview`, async function () {
+ const editor = await openEditor(serverUri);
+ // const { Cont|ainer } = require('inversify');
+ editor.getControl().setPosition({ lineNumber: 5, column: 13 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'Container');
+
+ await commands.executeCommand('editor.action.revealDefinition');
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.isTrue(editorManager.activeEditor.parent instanceof EditorPreviewWidget);
+ assert.equal(activeEditor.uri.toString(), inversifyUri.toString());
+ // export { |Container } from "./container/container";
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 3, column: 10 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+ });
+ }
+ });
+
+ describe('editor.action.peekDefinition', function () {
+
+ for (const preview of [false, true]) {
+ const from = 'an editor' + (preview ? ' preview' : '');
+ it('within ' + from, async function () {
+ const editor = await openEditor(serverUri, preview);
+ // con|tainer.load(backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 4 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+
+ await openPeek(editor);
+ await openReference();
+
+ const activeEditor = MonacoEditor.get(editorManager.activeEditor);
+ assert.equal(editorManager.activeEditor.parent instanceof EditorPreviewWidget, preview);
+ assert.equal(activeEditor.uri.toString(), serverUri.toString());
+ // const |container = new Container();
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 11, column: 7 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'container');
+
+ await closePeek();
+ });
+
+ it(`from ${from} to another editor`, async function () {
+ await editorManager.open(inversifyUri, { mode: 'open' });
+
+ const editor = await openEditor(serverUri, preview);
+ // const { Cont|ainer } = require('inversify');
+ editor.getControl().setPosition({ lineNumber: 5, column: 13 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'Container');
+
+ await openPeek(editor);
+ await openReference();
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.isFalse(editorManager.activeEditor.parent instanceof EditorPreviewWidget);
+ assert.equal(activeEditor.uri.toString(), inversifyUri.toString());
+ // export { |Container } from "./container/container";
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 3, column: 10 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+
+ await closePeek();
+ });
+
+ it(`from ${from} to an editor preview`, async function () {
+ const editor = await openEditor(serverUri);
+ // const { Cont|ainer } = require('inversify');
+ editor.getControl().setPosition({ lineNumber: 5, column: 13 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'Container');
+
+ await openPeek(editor);
+ await openReference();
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.isTrue(editorManager.activeEditor.parent instanceof EditorPreviewWidget);
+ assert.equal(activeEditor.uri.toString(), inversifyUri.toString());
+ // export { |Container } from "./container/container";
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 3, column: 10 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+
+ await closePeek();
+ });
+ }
+ });
+
+ it('editor.action.triggerSuggest', async function () {
+ const editor = await openEditor(serverUri);
+ // const { [|Container] } = require('inversify');
+ editor.getControl().setPosition({ lineNumber: 5, column: 9 });
+ editor.getControl().setSelection({ startLineNumber: 5, startColumn: 9, endLineNumber: 5, endColumn: 18 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'Container');
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('suggestWidgetVisible'));
+
+ await commands.executeCommand('editor.action.triggerSuggest');
+ await waitForAnimation(() => contextKeyService.match('suggestWidgetVisible'));
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(contextKeyService.match('suggestWidgetVisible'));
+
+ keybindings.dispatchKeyDown('Enter');
+ await waitForAnimation(() => !contextKeyService.match('suggestWidgetVisible'));
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('suggestWidgetVisible'));
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.equal(activeEditor.uri.toString(), serverUri.toString());
+ // const { Container| } = require('inversify');
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 5, column: 18 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+ });
+
+ it('editor.action.rename', async function () {
+ const editor = await openEditor(serverUri);
+ // const |container = new Container();
+ editor.getControl().setPosition({ lineNumber: 11, column: 7 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('renameInputVisible'));
+
+ const renaming = commands.executeCommand('editor.action.rename');
+ await waitForAnimation(() => contextKeyService.match('renameInputVisible')
+ && document.activeElement instanceof HTMLInputElement
+ && document.activeElement.selectionEnd === 'container'.length);
+ assert.isFalse(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(contextKeyService.match('renameInputVisible'));
+
+ const input = document.activeElement;
+ if (!(input instanceof HTMLInputElement)) {
+ assert.fail('expected focused input, but: ' + input);
+ return;
+ }
+
+ input.value = 'foo';
+ keybindings.dispatchKeyDown('Enter', input);
+
+ await renaming;
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('renameInputVisible'));
+
+ const activeEditor = MonacoEditor.getActive(editorManager);
+ assert.equal(activeEditor.uri.toString(), serverUri.toString());
+ // const |foo = new Container();
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 11, column: 7 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'foo');
+ });
+
+ it('editor.action.triggerParameterHints', async function () {
+ const editor = await openEditor(serverUri);
+ // container.load(|backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 16 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'backendApplicationModule');
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('parameterHintsVisible'));
+
+ await commands.executeCommand('editor.action.triggerParameterHints');
+ await waitForAnimation(() => contextKeyService.match('parameterHintsVisible'));
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(contextKeyService.match('parameterHintsVisible'));
+
+ keybindings.dispatchKeyDown('Escape');
+ await waitForAnimation(() => !contextKeyService.match('parameterHintsVisible'));
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(contextKeyService.match('parameterHintsVisible'));
+ });
+
+ it('editor.action.showHover', async function () {
+ const editor = await openEditor(serverUri);
+ // container.load(|backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 16 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'backendApplicationModule');
+
+ const hover = editor.getControl()._contributions['editor.contrib.hover'];
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(hover.contentWidget.isVisible);
+
+ await commands.executeCommand('editor.action.showHover');
+ await waitForAnimation(() => hover.contentWidget.isVisible);
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isTrue(hover.contentWidget.isVisible);
+
+ assert.deepEqual(nodeAsString(hover.contentWidget._domNode), `
+DIV {
+ DIV {
+ DIV {
+ DIV {
+ DIV {
+ SPAN {
+ DIV {
+ SPAN {
+ "const"
+ }
+ SPAN {
+ " "
+ }
+ SPAN {
+ "backendApplicationModule"
+ }
+ SPAN {
+ ": "
+ }
+ SPAN {
+ "ContainerModule"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+`);
+
+ keybindings.dispatchKeyDown('Escape');
+ await waitForAnimation(() => !hover.contentWidget.isVisible);
+
+ assert.isTrue(contextKeyService.match('editorTextFocus'));
+ assert.isFalse(hover.contentWidget.isVisible);
+ });
+
+ it('highligh semantic (write) occurences', async function () {
+ const editor = await openEditor(serverUri);
+ // const |container = new Container();
+ const lineNumber = 11;
+ const column = 7;
+ const endColumn = column + 'container'.length;
+
+ const hasWriteDecoration = () => {
+ for (const decoration of editor.getControl().getModel().getLineDecorations(lineNumber)) {
+ if (decoration.range.startColumn === column && decoration.range.endColumn === endColumn && decoration.options.className === 'wordHighlightStrong') {
+ return true;
+ }
+ }
+ return false;
+ };
+ assert.isFalse(hasWriteDecoration());
+
+ editor.getControl().setPosition({ lineNumber, column });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+ // highlight occurences is not trigged on the explicit position change, so move a cursor as a user
+ keybindings.dispatchKeyDown('ArrowRight');
+ await waitForAnimation(() => hasWriteDecoration());
+
+ assert.isTrue(hasWriteDecoration());
+ });
+
+ it('editor.action.goToImplementation', async function () {
+ const editor = await openEditor(serverUri);
+ // con|tainer.load(backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 4 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+
+ await commands.executeCommand('editor.action.goToImplementation');
+
+ const activeEditor = MonacoEditor.get(editorManager.activeEditor);
+ assert.equal(activeEditor.uri.toString(), serverUri.toString());
+ // const |container = new Container();
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 11, column: 7 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'container');
+ });
+
+ it('editor.action.goToTypeDefinition', async function () {
+ const editor = await openEditor(serverUri);
+ // con|tainer.load(backendApplicationModule);
+ editor.getControl().setPosition({ lineNumber: 12, column: 4 });
+ assert.equal(editor.getControl().getModel().getWordAtPosition(editor.getControl().getPosition()).word, 'container');
+
+ await commands.executeCommand('editor.action.goToTypeDefinition');
+
+ const activeEditor = MonacoEditor.get(editorManager.activeEditor);
+ assert.equal(activeEditor.uri.toString(), containerUri.toString());
+ // declare class |Container implements interfaces.Container {
+ const { lineNumber, column } = activeEditor.getControl().getPosition();
+ assert.deepEqual({ lineNumber, column }, { lineNumber: 2, column: 15 });
+ assert.equal(activeEditor.getControl().getModel().getWordAtPosition({ lineNumber, column }).word, 'Container');
+ });
+
+ it('run reference code lens', async function () {
+ this.timeout(30000);
+
+ const globalValue = preferences.inspect('javascript.referencesCodeLens.enabled').globalValue;
+ toTearDown.push({ dispose: () => preferences.set('javascript.referencesCodeLens.enabled', globalValue, PreferenceScope.User) });
+
+ const editor = await openEditor(serverUri);
+
+ const codeLens = editor.getControl()._contributions['css.editor.codeLens'];
+ const codeLensNode = () => codeLens._lenses[0] && codeLens._lenses[0]._contentWidget && codeLens._lenses[0]._contentWidget._domNode;
+
+ assert.isFalse(document.contains(codeLensNode()));
+
+ // [export ]function load(raw) {
+ editor.getControl().getModel().applyEdits([{
+ range: monaco.Range.fromPositions({ lineNumber: 16, column: 1 }, { lineNumber: 16, column: 1 }),
+ forceMoveMarkers: false,
+ text: 'export '
+ }]);
+ await preferences.set('javascript.referencesCodeLens.enabled', true, PreferenceScope.User);
+ await waitForAnimation(() => document.contains(codeLensNode()));
+
+ const node = codeLensNode();
+ assert.isTrue(document.contains(node));
+ assert.equal(nodeAsString(node), `
+SPAN {
+ A {
+ "19 references"
+ }
+}
+`);
+
+ const link = node.getElementsByTagName('a').item(0);
+ link.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
+ await assertPeekOpened(editor);
+ await closePeek();
+ });
+
+});
diff --git a/examples/browser/.eslintrc.js b/examples/browser/.eslintrc.js
deleted file mode 100644
index be9cf1a1b3dff..0000000000000
--- a/examples/browser/.eslintrc.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/** @type {import('eslint').Linter.Config} */
-module.exports = {
- extends: [
- '../../configs/build.eslintrc.json'
- ],
- parserOptions: {
- tsconfigRootDir: __dirname,
- project: 'compile.tsconfig.json'
- }
-};
diff --git a/examples/browser/package.json b/examples/browser/package.json
index bb8becec87883..17256a7d5b442 100644
--- a/examples/browser/package.json
+++ b/examples/browser/package.json
@@ -55,13 +55,12 @@
},
"scripts": {
"prepare": "yarn run clean && yarn build",
- "lint": "theiaext lint",
"clean": "theia clean",
"build": "theia build --mode development",
"watch": "yarn build --watch",
"start": "theia start --plugins=local-dir:../../plugins",
"start:debug": "yarn start --log-level=debug",
- "test": "theia test . --test-spec=../api-tests/**/*.spec.js",
+ "test": "theia test . --plugins=local-dir:../../plugins --test-spec=../api-tests/**/*.spec.js",
"test:debug": "yarn test --test-inspect",
"coverage": "yarn test --test-coverage && yarn coverage:report",
"coverage:report": "nyc report --reporter=html",
@@ -70,4 +69,4 @@
"devDependencies": {
"@theia/cli": "^0.16.0"
}
-}
+}
\ No newline at end of file
diff --git a/packages/core/src/browser/keybinding.ts b/packages/core/src/browser/keybinding.ts
index 3b2d6a5f69136..429a1f50ac34c 100644
--- a/packages/core/src/browser/keybinding.ts
+++ b/packages/core/src/browser/keybinding.ts
@@ -571,6 +571,29 @@ export class KeybindingRegistry {
return true;
}
+ dispatchKeyDown(input: KeyboardEventInit | KeyCode | string, target: EventTarget = document.activeElement || window): void {
+ const eventInit = this.asKeyboardEventInit(input);
+ const emulatedKeyboardEvent = new KeyboardEvent('keydown', eventInit);
+ target.dispatchEvent(emulatedKeyboardEvent);
+ }
+ protected asKeyboardEventInit(input: KeyboardEventInit | KeyCode | string): KeyboardEventInit & Partial<{ keyCode: number }> {
+ if (typeof input === 'string') {
+ return this.asKeyboardEventInit(KeyCode.createKeyCode(input));
+ }
+ if (input instanceof KeyCode) {
+ return {
+ metaKey: input.meta,
+ shiftKey: input.shift,
+ altKey: input.alt,
+ ctrlKey: input.ctrl,
+ code: input.key && input.key.code,
+ key: (input && input.character) || (input.key && input.key.code),
+ keyCode: input.key && input.key.keyCode
+ };
+ }
+ return input;
+ }
+
/**
* Run the command matching to the given keyboard event.
*/
diff --git a/packages/core/src/browser/shell/application-shell.ts b/packages/core/src/browser/shell/application-shell.ts
index ba340a395e884..76091a9d83008 100644
--- a/packages/core/src/browser/shell/application-shell.ts
+++ b/packages/core/src/browser/shell/application-shell.ts
@@ -93,6 +93,7 @@ export class DockPanelRenderer implements DockLayout.IRenderer {
});
this.tabBarClasses.forEach(c => tabBar.addClass(c));
renderer.tabBar = tabBar;
+ tabBar.disposed.connect(() => renderer.dispose());
renderer.contextMenuPath = SHELL_TABBAR_CONTEXT_MENU;
tabBar.currentChanged.connect(this.onCurrentTabChanged, this);
return tabBar;
diff --git a/packages/core/src/browser/shell/side-panel-handler.ts b/packages/core/src/browser/shell/side-panel-handler.ts
index ff72e3c1f24a6..6667c1516d00e 100644
--- a/packages/core/src/browser/shell/side-panel-handler.ts
+++ b/packages/core/src/browser/shell/side-panel-handler.ts
@@ -138,6 +138,7 @@ export class SidePanelHandler {
suppressScrollX: true
});
tabBarRenderer.tabBar = sideBar;
+ sideBar.disposed.connect(() => tabBarRenderer.dispose());
tabBarRenderer.contextMenuPath = SHELL_TABBAR_CONTEXT_MENU;
sideBar.addClass('theia-app-' + side);
sideBar.addClass(LEFT_RIGHT_AREA_CLASS);
diff --git a/packages/core/src/browser/shell/tab-bars.ts b/packages/core/src/browser/shell/tab-bars.ts
index 3189561a3111d..58404dd03308c 100644
--- a/packages/core/src/browser/shell/tab-bars.ts
+++ b/packages/core/src/browser/shell/tab-bars.ts
@@ -94,6 +94,10 @@ export class TabBarRenderer extends TabBar.Renderer {
}
}
+ dispose(): void {
+ this.toDispose.dispose();
+ }
+
protected _tabBar?: TabBar;
protected readonly toDisposeOnTabBar = new DisposableCollection();
/**
@@ -101,6 +105,9 @@ export class TabBarRenderer extends TabBar.Renderer {
* is requested.
*/
set tabBar(tabBar: TabBar | undefined) {
+ if (this.toDispose.disposed) {
+ throw new Error('disposed');
+ }
if (this._tabBar === tabBar) {
return;
}
@@ -453,11 +460,21 @@ export class ScrollableTabBar extends TabBar {
private scrollBarFactory: () => PerfectScrollbar;
private pendingReveal?: Promise;
+ protected readonly toDispose = new DisposableCollection();
+
constructor(options?: TabBar.IOptions & PerfectScrollbar.Options) {
super(options);
this.scrollBarFactory = () => new PerfectScrollbar(this.scrollbarHost, options);
}
+ dispose(): void {
+ if (this.isDisposed) {
+ return;
+ }
+ super.dispose();
+ this.toDispose.dispose();
+ }
+
protected onAfterAttach(msg: Message): void {
if (!this.scrollBar) {
this.scrollBar = this.scrollBarFactory();
@@ -571,7 +588,7 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
super(options);
this.rewireDOM();
- this.tabBarToolbarRegistry.onDidChange(() => this.update());
+ this.toDispose.push(this.tabBarToolbarRegistry.onDidChange(() => this.update()));
}
/**
diff --git a/packages/monaco/src/typings/monaco/index.d.ts b/packages/monaco/src/typings/monaco/index.d.ts
index 562d2bf2f7d61..3c152acc2cf4d 100644
--- a/packages/monaco/src/typings/monaco/index.d.ts
+++ b/packages/monaco/src/typings/monaco/index.d.ts
@@ -68,12 +68,34 @@ declare module monaco.editor {
readonly _contributions: {
'editor.controller.quickOpenController': monaco.quickOpen.QuickOpenController
'editor.contrib.referencesController': monaco.referenceSearch.ReferencesController
+ 'editor.contrib.hover': ModesHoverController,
+ 'css.editor.codeLens': CodeLensContribution
}
readonly _modelData: {
cursor: ICursor
} | null;
}
+ // https://github.com/theia-ide/vscode/blob/d24b5f70c69b3e75cd10c6b5247a071265ccdd38/src/vs/editor/contrib/codelens/codelensController.ts#L24
+ export interface CodeLensContribution {
+ readonly _lenses: CodeLensWidget[];
+ }
+ export interface CodeLensWidget {
+ readonly _contentWidget?: CodeLensContentWidget;
+ }
+ export interface CodeLensContentWidget {
+ readonly _domNode: HTMLElement;
+ }
+
+ // https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/editor/contrib/hover/hover.ts#L31
+ export interface ModesHoverController {
+ readonly contentWidget: ModesContentHoverWidget
+ }
+ export interface ModesContentHoverWidget {
+ readonly isVisible: boolean;
+ readonly _domNode: HTMLElement;
+ }
+
// https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/editor/common/controller/cursor.ts#L169
export interface ICursor {
trigger(source: string, handlerId: string, payload: any): void;
@@ -749,7 +771,12 @@ declare module monaco.referenceSearch {
show(range: IRange): void;
hide(): void;
focus(): void;
+ _tree: ReferenceTree
+ }
+ export interface ReferenceTree {
+ getFocus(): ReferenceTreeElement[]
}
+ export interface ReferenceTreeElement { }
// https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts#L30
export interface ReferencesController extends IDisposable {
diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts
index cc655ee4b7ed6..9426ba7c7c1db 100644
--- a/packages/plugin-ext/src/common/plugin-api-rpc.ts
+++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts
@@ -190,6 +190,8 @@ export interface PluginManagerExt {
$updateStoragePath(path: string | undefined): Promise;
$activateByEvent(event: string): Promise;
+
+ $activatePlugin(id: string): Promise;
}
export interface CommandRegistryMain {
diff --git a/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts b/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
index 645340e7fecbf..4d5f15621854a 100644
--- a/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
+++ b/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
@@ -603,6 +603,14 @@ export class HostedPluginSupport {
}
}
+ async activatePlugin(id: string): Promise {
+ const activation = [];
+ for (const manager of this.managers.values()) {
+ activation.push(manager.$activatePlugin(id));
+ }
+ await Promise.all(activation);
+ }
+
protected createMeasurement(name: string): () => number {
const startMarker = `${name}-start`;
const endMarker = `${name}-end`;
diff --git a/packages/plugin-ext/src/main/browser/webview/webview.ts b/packages/plugin-ext/src/main/browser/webview/webview.ts
index 93162847c1e49..aa1f3003c8f83 100644
--- a/packages/plugin-ext/src/main/browser/webview/webview.ts
+++ b/packages/plugin-ext/src/main/browser/webview/webview.ts
@@ -280,7 +280,7 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget {
// Electron: workaround for https://github.com/electron/electron/issues/14258
// We have to detect keyboard events in the and dispatch them to our
// keybinding service because these events do not bubble to the parent window anymore.
- this.dispatchKeyDown(data);
+ this.keybindings.dispatchKeyDown(data, this.element);
}));
this.style();
@@ -395,17 +395,6 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget {
this.doSend('styles', { styles, activeTheme });
}
- protected dispatchKeyDown(event: KeyboardEventInit): void {
- // Create a fake KeyboardEvent from the data provided
- const emulatedKeyboardEvent = new KeyboardEvent('keydown', event);
- // Force override the target
- Object.defineProperty(emulatedKeyboardEvent, 'target', {
- get: () => this.element,
- });
- // And re-dispatch
- this.keybindings.run(emulatedKeyboardEvent);
- }
-
protected openLink(link: URI): void {
const supported = this.toSupportedLink(link);
if (supported) {
diff --git a/packages/plugin-ext/src/plugin/plugin-manager.ts b/packages/plugin-ext/src/plugin/plugin-manager.ts
index 2916b0d9d6dcc..d9834626802dd 100644
--- a/packages/plugin-ext/src/plugin/plugin-manager.ts
+++ b/packages/plugin-ext/src/plugin/plugin-manager.ts
@@ -84,6 +84,7 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
'onWebviewPanel'
]);
+ private configStorage: ConfigStorage | undefined;
private readonly registry = new Map();
private readonly activations = new Map Promise)[] | undefined>();
/** promises to whether loading each plugin has been successful */
@@ -196,14 +197,16 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
}
async $start(params: PluginManagerStartParams): Promise {
+ this.configStorage = params.configStorage;
+
const [plugins, foreignPlugins] = await this.host.init(params.plugins);
// add foreign plugins
for (const plugin of foreignPlugins) {
- this.registerPlugin(plugin, params.configStorage);
+ this.registerPlugin(plugin);
}
// add own plugins, before initialization
for (const plugin of plugins) {
- this.registerPlugin(plugin, params.configStorage);
+ this.registerPlugin(plugin);
}
// run eager plugins
@@ -219,15 +222,10 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
this.fireOnDidChange();
}
- protected registerPlugin(plugin: Plugin, configStorage: ConfigStorage): void {
+ protected registerPlugin(plugin: Plugin): void {
this.registry.set(plugin.model.id, plugin);
if (plugin.pluginPath && Array.isArray(plugin.rawModel.activationEvents)) {
- const activation = async () => {
- const title = `Activating ${plugin.model.displayName || plugin.model.name}`;
- const id = await this.notificationMain.$startProgress({ title, location: 'window' });
- await this.loadPlugin(plugin, configStorage);
- this.notificationMain.$stopProgress(id);
- };
+ const activation = () => this.$activatePlugin(plugin.model.id);
// an internal activation event is a subject to change
this.setActivation(`onPlugin:${plugin.model.id}`, activation);
const unsupportedActivationEvents = plugin.rawModel.activationEvents.filter(e => !PluginManagerExtImpl.SUPPORTED_ACTIVATION_EVENTS.has(e.split(':')[0]));
@@ -261,31 +259,39 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
let loading = this.loadedPlugins.get(plugin.model.id);
if (!loading) {
loading = (async () => {
- if (plugin.rawModel.extensionDependencies) {
- for (const dependencyId of plugin.rawModel.extensionDependencies) {
- const dependency = this.registry.get(dependencyId.toLowerCase());
- const id = plugin.model.displayName || plugin.model.id;
- if (dependency) {
- const depId = dependency.model.displayName || dependency.model.id;
- const loadedSuccessfully = await this.loadPlugin(dependency, configStorage, visited);
- if (!loadedSuccessfully) {
- const message = `Cannot activate extension '${id}' because it depends on extension '${depId}', which failed to activate.`;
+ const progressId = await this.notificationMain.$startProgress({
+ title: `Activating ${plugin.model.displayName || plugin.model.name}`,
+ location: 'window'
+ });
+ try {
+ if (plugin.rawModel.extensionDependencies) {
+ for (const dependencyId of plugin.rawModel.extensionDependencies) {
+ const dependency = this.registry.get(dependencyId.toLowerCase());
+ const id = plugin.model.displayName || plugin.model.id;
+ if (dependency) {
+ const depId = dependency.model.displayName || dependency.model.id;
+ const loadedSuccessfully = await this.loadPlugin(dependency, configStorage, visited);
+ if (!loadedSuccessfully) {
+ const message = `Cannot activate extension '${id}' because it depends on extension '${depId}', which failed to activate.`;
+ this.messageRegistryProxy.$showMessage(MainMessageType.Error, message, {}, []);
+ return false;
+ }
+ } else {
+ const message = `Cannot activate the '${id}' extension because it depends on the '${dependencyId}' extension, which is not installed.`;
this.messageRegistryProxy.$showMessage(MainMessageType.Error, message, {}, []);
+ console.warn(message);
return false;
}
- } else {
- const message = `Cannot activate the '${id}' extension because it depends on the '${dependencyId}' extension, which is not installed.`;
- this.messageRegistryProxy.$showMessage(MainMessageType.Error, message, {}, []);
- console.warn(message);
- return false;
}
}
- }
- let pluginMain = this.host.loadPlugin(plugin);
- // see https://github.com/TypeFox/vscode/blob/70b8db24a37fafc77247de7f7cb5bb0195120ed0/src/vs/workbench/api/common/extHostExtensionService.ts#L372-L376
- pluginMain = pluginMain || {};
- return this.startPlugin(plugin, configStorage, pluginMain);
+ let pluginMain = this.host.loadPlugin(plugin);
+ // see https://github.com/TypeFox/vscode/blob/70b8db24a37fafc77247de7f7cb5bb0195120ed0/src/vs/workbench/api/common/extHostExtensionService.ts#L372-L376
+ pluginMain = pluginMain || {};
+ return await this.startPlugin(plugin, configStorage, pluginMain);
+ } finally {
+ this.notificationMain.$stopProgress(progressId);
+ }
})();
}
this.loadedPlugins.set(plugin.model.id, loading);
@@ -293,6 +299,9 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
}
async $updateStoragePath(path: string | undefined): Promise {
+ if (this.configStorage) {
+ this.configStorage.hostStoragePath = path;
+ }
this.pluginContextsMap.forEach((pluginContext: theia.PluginContext, pluginId: string) => {
pluginContext.storagePath = path ? join(path, pluginId) : undefined;
});
@@ -309,6 +318,13 @@ export class PluginManagerExtImpl implements PluginManagerExt, PluginManager {
}
}
+ async $activatePlugin(id: string): Promise {
+ const plugin = this.registry.get(id);
+ if (plugin && this.configStorage) {
+ await this.loadPlugin(plugin, this.configStorage);
+ }
+ }
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async startPlugin(plugin: Plugin, configStorage: ConfigStorage, pluginMain: any): Promise {
const subscriptions: theia.Disposable[] = [];
diff --git a/tsconfig.json b/tsconfig.json
index 63b84501a0df6..f135cd45e838e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,7 +8,8 @@
"include": [
"dev-packages/*/src",
"packages/*/src",
- "examples/*/src"
+ "examples/*/src",
+ "examples/browser/src-gen"
],
"compilerOptions": {
"baseUrl": ".",
@@ -162,4 +163,4 @@
]
}
}
-}
+}
\ No newline at end of file