Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add java-debug extension based on vscode-java-debug #3613

Merged
merged 10 commits into from
Dec 6, 2018
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cache:
- packages/filesystem/node_modules
- packages/getting-started/node_modules
- packages/git/node_modules
- packages/java-debug/node_modules
- packages/java/node_modules
- packages/json/node_modules
- packages/keymaps/node_modules
Expand Down
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"name": "Launch Backend",
"program": "${workspaceRoot}/examples/browser/src-gen/backend/main.js",
"args": [
"--log-level=debug",
"--hostname=0.0.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hello, I don't see how this change it is related to this feature ?

Copy link
Member Author

@akosyakov akosyakov Nov 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is related because I needed it to debug extensions

"--port=3000",
"--no-cluster",
"--app-project-path=${workspaceRoot}/examples/browser",
Expand Down
1 change: 1 addition & 0 deletions configs/warnings.tslint.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"rules": {
"deprecation": true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hello, I don't see how this change it is related to this feature ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've deprecated some APIs and want other developers to notice it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my point is why deprecated notice is not discussed first
and why it should be deprecated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, let's discuss deprecation on Tuesday

btw it is just warning, it won't break builds and so on. There is also no APIs broken in core and developers can stop using moved APIs over time.

"await-promise": {
"severity": "warning",
"options": [
Expand Down
1 change: 1 addition & 0 deletions examples/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@theia/getting-started": "^0.3.17",
"@theia/git": "^0.3.17",
"@theia/java": "^0.3.17",
"@theia/java-debug": "^0.3.17",
"@theia/json": "^0.3.17",
"@theia/keymaps": "^0.3.17",
"@theia/languages": "^0.3.17",
Expand Down
2 changes: 1 addition & 1 deletion examples/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"//": [
"`@theia/plugin-ext` and `@theia/plugin-ext-vscode` are missing due to https://github.com/theia-ide/theia/issues/3723",
"`@theia/debug` and `@theia/debug-nodejs` are removed due to https://github.com/theia-ide/theia/issues/3716"
"`@theia/debug`, `@theia/debug-nodejs` and `@theia/java-debug` are removed due to https://github.com/theia-ide/theia/issues/3716"
],
"dependencies": {
"@theia/callhierarchy": "^0.3.17",
Expand Down
26 changes: 20 additions & 6 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@ import {
bindContributionProvider,
SelectionService,
ResourceProvider, ResourceResolver, DefaultResourceProvider,
CommandContribution, CommandRegistry, CommandService,
CommandContribution, CommandRegistry, CommandService, commandServicePath,
MenuModelRegistry, MenuContribution,
MessageService,
MessageClient,
InMemoryResources
InMemoryResources,
messageServicePath
} from '../common';
import { KeybindingRegistry, KeybindingContext, KeybindingContribution } from './keybinding';
import { FrontendApplication, FrontendApplicationContribution, DefaultFrontendApplicationContribution } from './frontend-application';
import { DefaultOpenerService, OpenerService, OpenHandler } from './opener-service';
import { HttpOpenHandler } from './http-open-handler';
import { CommonFrontendContribution } from './common-frontend-contribution';
import {
QuickOpenService, QuickCommandService, QuickCommandFrontendContribution, QuickPickService, QuickOpenContribution,
QuickOpenService, QuickCommandService, QuickCommandFrontendContribution, QuickOpenContribution,
QuickOpenHandlerRegistry, CommandQuickOpenContribution, HelpQuickOpenHandler,
QuickOpenFrontendContribution, PrefixQuickOpenService, QuickInputService
} from './quick-open';
Expand Down Expand Up @@ -64,6 +65,8 @@ import { FrontendApplicationStateService } from './frontend-application-state';
import { JsonSchemaStore } from './json-schema-store';
import { TabBarToolbarRegistry, TabBarToolbarContribution, TabBarToolbarFactory, TabBarToolbar } from './shell/tab-bar-toolbar';
import { bindCorePreferences } from './core-preferences';
import { QuickPickServiceImpl } from './quick-open/quick-pick-service-impl';
import { QuickPickService, quickPickServicePath } from '../common/quick-pick-service';

export const frontendApplicationModule = new ContainerModule((bind, unbind, isBound, rebind) => {
const themeService = ThemeService.get();
Expand Down Expand Up @@ -124,7 +127,10 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo
bind(ResourceResolver).toService(InMemoryResources);

bind(SelectionService).toSelf().inSingletonScope();
bind(CommandRegistry).toSelf().inSingletonScope();
bind(CommandRegistry).toSelf().inSingletonScope().onActivation(({ container }, registry) => {
WebSocketConnectionProvider.createProxy(container, commandServicePath, registry);
return registry;
});
bind(CommandService).toService(CommandRegistry);
bindContributionProvider(bind, CommandContribution);
bind(QuickOpenContribution).to(CommandQuickOpenContribution);
Expand All @@ -137,22 +143,30 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo
bindContributionProvider(bind, KeybindingContribution);

bind(MessageClient).toSelf().inSingletonScope();
bind(MessageService).toSelf().inSingletonScope();
bind(MessageService).toSelf().inSingletonScope().onActivation(({ container }, messages) => {
const client = container.get(MessageClient);
WebSocketConnectionProvider.createProxy(container, messageServicePath, client);
return messages;
});

bind(CommonFrontendContribution).toSelf().inSingletonScope();
[FrontendApplicationContribution, CommandContribution, KeybindingContribution, MenuContribution].forEach(serviceIdentifier =>
bind(serviceIdentifier).toService(CommonFrontendContribution)
);

bind(QuickOpenService).toSelf().inSingletonScope();
bind(QuickPickService).toSelf().inSingletonScope();
bind(QuickInputService).toSelf().inSingletonScope();
bind(QuickCommandService).toSelf().inSingletonScope();
bind(QuickCommandFrontendContribution).toSelf().inSingletonScope();
[CommandContribution, KeybindingContribution, MenuContribution].forEach(serviceIdentifier =>
bind(serviceIdentifier).toService(QuickCommandFrontendContribution)
);

bind(QuickPickService).to(QuickPickServiceImpl).inSingletonScope().onActivation(({ container }, quickPickService) => {
WebSocketConnectionProvider.createProxy(container, quickPickServicePath, quickPickService);
return quickPickService;
});

bind(PrefixQuickOpenService).toSelf().inSingletonScope();
bindContributionProvider(bind, QuickOpenContribution);
bind(QuickOpenHandlerRegistry).toSelf().inSingletonScope();
Expand Down
85 changes: 85 additions & 0 deletions packages/core/src/browser/quick-open/quick-pick-service-impl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/********************************************************************************
* Copyright (C) 2018 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 { injectable, inject } from 'inversify';
import { QuickOpenItem, QuickOpenMode, QuickOpenGroupItem, QuickOpenItemOptions } from './quick-open-model';
import { QuickOpenService } from './quick-open-service';
import { QuickPickService, QuickPickOptions, QuickPickItem, QuickPickSeparator, QuickPickValue } from '../../common/quick-pick-service';

@injectable()
export class QuickPickServiceImpl implements QuickPickService {

@inject(QuickOpenService)
protected readonly quickOpenService: QuickOpenService;

show(elements: string[], options?: QuickPickOptions): Promise<string | undefined>;
show<T>(elements: QuickPickItem<T>[], options?: QuickPickOptions): Promise<T | undefined>;
async show(elements: (string | QuickPickItem<Object>)[], options?: QuickPickOptions): Promise<Object | undefined> {
return new Promise<Object | undefined>(resolve => {
const items = this.toItems(elements, resolve);
if (items.length === 0) {
resolve(undefined);
return;
}
if (items.length === 1) {
items[0].run(QuickOpenMode.OPEN);
return;
}
this.quickOpenService.open({ onType: (_, acceptor) => acceptor(items) }, Object.assign({
onClose: () => resolve(undefined),
fuzzyMatchLabel: true,
fuzzyMatchDescription: true
}, options));
});
}
protected toItems(elements: (string | QuickPickItem<Object>)[], resolve: (element: Object) => void): QuickOpenItem[] {
const items: QuickOpenItem[] = [];
let groupLabel: string | undefined;
for (const element of elements) {
if (QuickPickSeparator.is(element)) {
groupLabel = element.label;
} else {
const options = this.toItemOptions(element, resolve);
if (groupLabel) {
items.push(new QuickOpenGroupItem(Object.assign(options, { groupLabel, showBorder: true })));
groupLabel = undefined;
} else {
items.push(new QuickOpenItem(options));
}
}
}
return items;
}
protected toItemOptions(element: string | QuickPickValue<Object>, resolve: (element: Object) => void): QuickOpenItemOptions {
const label = typeof element === 'string' ? element : element.label;
const value = typeof element === 'string' ? element : element.value;
const description = typeof element === 'string' ? undefined : element.description;
const iconClass = typeof element === 'string' ? undefined : element.iconClass;
return {
label,
description,
iconClass,
run: mode => {
if (mode !== QuickOpenMode.OPEN) {
return false;
}
resolve(value);
return true;
}
};
}

}
124 changes: 25 additions & 99 deletions packages/core/src/browser/quick-open/quick-pick-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,102 +14,28 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable, inject } from 'inversify';
import { QuickOpenItem, QuickOpenMode, QuickOpenGroupItem, QuickOpenItemOptions } from './quick-open-model';
import { QuickOpenService } from './quick-open-service';

export type QuickPickItem<T> = QuickPickValue<T> | QuickPickSeparator;

export interface QuickPickSeparator {
type: 'separator'
label: string
}
export namespace QuickPickSeparator {
export function is(item: string | QuickPickItem<Object>): item is QuickPickSeparator {
return typeof item === 'object' && 'type' in item && item['type'] === 'separator';
}
}

export interface QuickPickValue<T> {
label: string
value: T
description?: string
iconClass?: string
}

export interface QuickPickOptions {
placeholder?: string
/**
* default: true
*/
fuzzyMatchLabel?: boolean
/**
* default: true
*/
fuzzyMatchDescription?: boolean
}

@injectable()
export class QuickPickService {

@inject(QuickOpenService)
protected readonly quickOpenService: QuickOpenService;

show(elements: string[], options?: QuickPickOptions): Promise<string | undefined>;
show<T>(elements: QuickPickItem<T>[], options?: QuickPickOptions): Promise<T | undefined>;
async show(elements: (string | QuickPickItem<Object>)[], options?: QuickPickOptions): Promise<Object | undefined> {
return new Promise<Object | undefined>(resolve => {
const items = this.toItems(elements, resolve);
if (items.length === 0) {
resolve(undefined);
return;
}
if (items.length === 1) {
items[0].run(QuickOpenMode.OPEN);
return;
}
this.quickOpenService.open({ onType: (_, acceptor) => acceptor(items) }, Object.assign({
onClose: () => resolve(undefined),
fuzzyMatchLabel: true,
fuzzyMatchDescription: true
}, options));
});
}
protected toItems(elements: (string | QuickPickItem<Object>)[], resolve: (element: Object) => void): QuickOpenItem[] {
const items: QuickOpenItem[] = [];
let groupLabel: string | undefined;
for (const element of elements) {
if (QuickPickSeparator.is(element)) {
groupLabel = element.label;
} else {
const options = this.toItemOptions(element, resolve);
if (groupLabel) {
items.push(new QuickOpenGroupItem(Object.assign(options, { groupLabel, showBorder: true })));
groupLabel = undefined;
} else {
items.push(new QuickOpenItem(options));
}
}
}
return items;
}
protected toItemOptions(element: string | QuickPickValue<Object>, resolve: (element: Object) => void): QuickOpenItemOptions {
const label = typeof element === 'string' ? element : element.label;
const value = typeof element === 'string' ? element : element.value;
const description = typeof element === 'string' ? undefined : element.description;
const iconClass = typeof element === 'string' ? undefined : element.iconClass;
return {
label,
description,
iconClass,
run: mode => {
if (mode !== QuickOpenMode.OPEN) {
return false;
}
resolve(value);
return true;
}
};
}

}
import * as common from '../../common/quick-pick-service';
/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export const QuickPickService = common.QuickPickService;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this service is becoming deprecated, what is the reason behind ?

Copy link
Member Author

@akosyakov akosyakov Nov 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QuickPickService can be used on the backend as well now, because of it interface declarations were moved to common from browser. Developers should update imports as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're telling the "how", not "why" ?

Copy link
Member Author

@akosyakov akosyakov Nov 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be used in the java debug adapter contribution, please use find references on common.QuickPickService

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akosyakov I see the choice you've used, not the reason why service should be callable from browser and node.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not the reason why service should be callable from browser and node.

Not sure what you mean.
(1) we want to keep the java debug adapter contribution as close as possible to the provder implementatino from vscode-java-debug to catch up fast, so these calls should be there
(2) in the scope of the same web socket connection, we want to allow access of frontend services from the backend generally , as @svenefftinge explained here. It is fine for us to move them as we need them for PRs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akosyakov The main point is that there was no discussion previously. it was just a comment on a PR. Also planned tasks on Theia from TypeFox are unclear. Also why the word fast is used ?
Also, the word we should be replaced by TypeFox probably ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benoitf We all have many decisions to make on each PR. If there are some that you care about and want to discuss, please do so (like you did here).
It is pretty hard to know upfront what things others might want to discuss and we couldn't move anywhere if we need to have meetings for every decision. That is IMHO one important reason we are having PRs. Someone proposes something and people who care chime in.
But your comment sounds a bit alarming, so I think we should discuss this in tomorrow's meeting. I added it the agenda.

/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export type QuickPickService = common.QuickPickService;
/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export type QuickPickOptions = common.QuickPickOptions;
/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export type QuickPickItem<T> = common.QuickPickItem<T>;
/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export type QuickPickSeparator = common.QuickPickSeparator;
/**
* @deprecated import from `@theia/core/lib/common/quick-pick-service` instead
*/
export type QuickPickValue<T> = common.QuickPickValue<T>;
8 changes: 5 additions & 3 deletions packages/core/src/common/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export interface CommandContribution {
registerCommands(commands: CommandRegistry): void;
}

export const commandServicePath = '/services/commands';
export const CommandService = Symbol('CommandService');
/**
* The command service should be used to execute commands.
Expand Down Expand Up @@ -234,13 +235,14 @@ export class CommandRegistry implements CommandService {
* Reject if a command cannot be executed.
*/
// tslint:disable-next-line:no-any
executeCommand<T>(command: string, ...args: any[]): Promise<T | undefined> {
async executeCommand<T>(command: string, ...args: any[]): Promise<T | undefined> {
const handler = this.getActiveHandler(command, ...args);
if (handler) {
return Promise.resolve(handler.execute(...args));
const result = await handler.execute(...args);
return result;
}
const argsMessage = args && args.length > 0 ? ` (args: ${JSON.stringify(args)})` : '';
return Promise.reject(`The command '${command}' cannot be executed. There are no active handlers available for the command.${argsMessage}`);
throw new Error(`The command '${command}' cannot be executed. There are no active handlers available for the command.${argsMessage}`);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/common/disposable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class DisposableCollection implements Disposable {

private disposingElements = false;
dispose(): void {
if (this.disposed) {
if (this.disposed || this.disposingElements) {
return;
}
this.disposingElements = true;
Expand Down
Loading