Skip to content

Commit d49037a

Browse files
author
Akos Kitta
committed
Link resolved for lib/boards manager.
Closes arduino#1442 Signed-off-by: Akos Kitta <[email protected]>
1 parent 42f6f43 commit d49037a

File tree

6 files changed

+160
-26
lines changed

6 files changed

+160
-26
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+3
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ import { OutputEditorFactory } from './theia/output/output-editor-factory';
338338
import { StartupTaskProvider } from '../electron-common/startup-task';
339339
import { DeleteSketch } from './contributions/delete-sketch';
340340
import { UserFields } from './contributions/user-fields';
341+
import { OpenHandler } from '@theia/core/lib/browser/opener-service';
341342

342343
const registerArduinoThemes = () => {
343344
const themes: MonacoThemeJson[] = [
@@ -402,6 +403,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
402403
bind(FrontendApplicationContribution).toService(
403404
LibraryListWidgetFrontendContribution
404405
);
406+
bind(OpenHandler).toService(LibraryListWidgetFrontendContribution);
405407

406408
// Sketch list service
407409
bind(SketchesService)
@@ -468,6 +470,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
468470
bind(FrontendApplicationContribution).toService(
469471
BoardsListWidgetFrontendContribution
470472
);
473+
bind(OpenHandler).toService(BoardsListWidgetFrontendContribution);
471474

472475
// Board select dialog
473476
bind(BoardsConfigDialogWidget).toSelf().inSingletonScope();

arduino-ide-extension/src/browser/boards/boards-widget-frontend-contribution.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { injectable } from '@theia/core/shared/inversify';
22
import { BoardsListWidget } from './boards-list-widget';
3-
import type {
3+
import {
44
BoardSearch,
55
BoardsPackage,
66
} from '../../common/protocol/boards-service';
@@ -11,6 +11,8 @@ export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendCont
1111
BoardsPackage,
1212
BoardSearch
1313
> {
14+
protected readonly openerAuthority = 'boardsmanager';
15+
1416
constructor() {
1517
super({
1618
widgetId: BoardsListWidget.WIDGET_ID,
@@ -24,7 +26,22 @@ export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendCont
2426
});
2527
}
2628

27-
override async initializeLayout(): Promise<void> {
28-
this.openView();
29+
protected parsePath(path: string): Omit<BoardSearch, 'query'> | undefined {
30+
const segments = this.normalizedSegmentsOf(path, 1);
31+
if (!segments) {
32+
return undefined;
33+
}
34+
const [type] = segments;
35+
if (!type) {
36+
return {
37+
type: 'All',
38+
};
39+
}
40+
if (BoardSearch.Type.is(type)) {
41+
return {
42+
type,
43+
};
44+
}
45+
return undefined;
2946
}
3047
}
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
import { nls } from '@theia/core/lib/common';
2+
import { MenuModelRegistry } from '@theia/core/lib/common/menu';
13
import { injectable } from '@theia/core/shared/inversify';
2-
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
3-
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
4-
import { MenuModelRegistry } from '@theia/core';
5-
import { LibraryListWidget } from './library-list-widget';
4+
import { LibraryPackage, LibrarySearch } from '../../common/protocol';
65
import { ArduinoMenus } from '../menu/arduino-menus';
7-
import { nls } from '@theia/core/lib/common';
6+
import { ListWidgetFrontendContribution } from '../widgets/component-list/list-widget-frontend-contribution';
7+
import { LibraryListWidget } from './library-list-widget';
88

99
@injectable()
10-
export class LibraryListWidgetFrontendContribution
11-
extends AbstractViewContribution<LibraryListWidget>
12-
implements FrontendApplicationContribution
13-
{
10+
export class LibraryListWidgetFrontendContribution extends ListWidgetFrontendContribution<
11+
LibraryPackage,
12+
LibrarySearch
13+
> {
14+
protected readonly openerAuthority = 'librarymanager';
15+
1416
constructor() {
1517
super({
1618
widgetId: LibraryListWidget.WIDGET_ID,
@@ -24,10 +26,6 @@ export class LibraryListWidgetFrontendContribution
2426
});
2527
}
2628

27-
async initializeLayout(): Promise<void> {
28-
this.openView();
29-
}
30-
3129
override registerMenus(menus: MenuModelRegistry): void {
3230
if (this.toggleCommand) {
3331
menus.registerMenuAction(ArduinoMenus.TOOLS__MAIN_GROUP, {
@@ -40,4 +38,31 @@ export class LibraryListWidgetFrontendContribution
4038
});
4139
}
4240
}
41+
42+
protected parsePath(path: string): Omit<LibrarySearch, 'query'> | undefined {
43+
const segments = this.normalizedSegmentsOf(path, 2);
44+
if (!segments) {
45+
return undefined;
46+
}
47+
const [type, topic] = segments;
48+
if (!type && !topic) {
49+
return {
50+
type: 'All',
51+
};
52+
}
53+
if (LibrarySearch.Type.is(type)) {
54+
if (!topic) {
55+
return {
56+
type,
57+
};
58+
}
59+
if (LibrarySearch.Topic.is(topic)) {
60+
return {
61+
type,
62+
topic,
63+
};
64+
}
65+
}
66+
return undefined;
67+
}
4368
}
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,92 @@
1-
import { injectable } from '@theia/core/shared/inversify';
21
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
2+
import {
3+
OpenerOptions,
4+
OpenHandler,
5+
} from '@theia/core/lib/browser/opener-service';
36
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
7+
import { MenuModelRegistry } from '@theia/core/lib/common/menu';
8+
import { URI } from '@theia/core/lib/common/uri';
9+
import { injectable } from '@theia/core/shared/inversify';
10+
import { Searchable } from '../../../common/protocol';
411
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
512
import { ListWidget } from './list-widget';
6-
import { Searchable } from '../../../common/protocol';
713

814
@injectable()
915
export abstract class ListWidgetFrontendContribution<
1016
T extends ArduinoComponent,
1117
S extends Searchable.Options
1218
>
1319
extends AbstractViewContribution<ListWidget<T, S>>
14-
implements FrontendApplicationContribution
20+
implements FrontendApplicationContribution, OpenHandler
1521
{
22+
protected abstract readonly openerAuthority: string;
23+
readonly id: string = `http-opener-${this.viewId}`;
24+
1625
async initializeLayout(): Promise<void> {
17-
// TS requires at least one method from `FrontendApplicationContribution`.
18-
// Expected to be empty.
26+
this.openView();
1927
}
2028

21-
override registerMenus(): void {
29+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
30+
override registerMenus(_: MenuModelRegistry): void {
2231
// NOOP
2332
}
33+
34+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
35+
canHandle(uri: URI, _?: OpenerOptions): number {
36+
// `500` is the default HTTP opener in Theia. IDE2 has higher priority.
37+
// https://github.com/eclipse-theia/theia/blob/b75b6144b0ffea06a549294903c374fa642135e4/packages/core/src/browser/http-open-handler.ts#L39
38+
return uri.scheme === 'http' && uri.authority === this.openerAuthority
39+
? 501
40+
: 0;
41+
}
42+
43+
async open(
44+
uri: URI,
45+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
46+
_?: OpenerOptions | undefined
47+
): Promise<void> {
48+
const searchOptions = this.parse(uri);
49+
if (!searchOptions) {
50+
console.warn(
51+
`Failed to parse URI into a search options. URI: ${uri.toString()}`
52+
);
53+
return;
54+
}
55+
56+
const widget = await this.openView({
57+
activate: true,
58+
reveal: true,
59+
});
60+
if (!widget) {
61+
console.warn(`Failed to open view for URI: ${uri.toString()}`);
62+
return;
63+
}
64+
65+
widget.refresh(searchOptions);
66+
}
67+
68+
protected parse(uri: URI): S | undefined {
69+
const refinements = this.parsePath(uri.path.toString());
70+
if (!refinements) {
71+
return undefined;
72+
}
73+
return { ...refinements, query: uri.fragment } as S;
74+
}
75+
76+
protected normalizedSegmentsOf(
77+
path: string,
78+
maxSegmentCount: number
79+
): string[] | undefined {
80+
// /
81+
// /All
82+
// /All/Device%20Control
83+
// /All/Display
84+
const segments = path.split('/').slice(1).map(decodeURIComponent);
85+
if (segments.length > maxSegmentCount) {
86+
return undefined;
87+
}
88+
return segments;
89+
}
90+
91+
protected abstract parsePath(path: string): Omit<S, 'query'> | undefined;
2492
}

arduino-ide-extension/src/common/protocol/boards-service.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import { Searchable } from './searchable';
33
import { Installable } from './installable';
44
import { ArduinoComponent } from './arduino-component';
55
import { nls } from '@theia/core/lib/common/nls';
6-
import { All, Contributed, Partner, Type, Updatable } from '../nls';
6+
import {
7+
All,
8+
Contributed,
9+
Partner,
10+
Type as TypeLabel,
11+
Updatable,
12+
} from '../nls';
713

814
export type AvailablePorts = Record<string, [Port, Array<Board>]>;
915
export namespace AvailablePorts {
@@ -161,6 +167,11 @@ export namespace BoardSearch {
161167
'Arduino@Heart',
162168
] as const;
163169
export type Type = typeof TypeLiterals[number];
170+
export namespace Type {
171+
export function is(arg: unknown): arg is Type {
172+
return typeof arg === 'string' && TypeLiterals.includes(arg as Type);
173+
}
174+
}
164175
export const TypeLabels: Record<Type, string> = {
165176
All: All,
166177
Updatable: Updatable,
@@ -177,7 +188,7 @@ export namespace BoardSearch {
177188
keyof Omit<BoardSearch, 'query'>,
178189
string
179190
> = {
180-
type: Type,
191+
type: TypeLabel,
181192
};
182193
}
183194

arduino-ide-extension/src/common/protocol/library-service.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
Partner,
99
Recommended,
1010
Retired,
11-
Type,
11+
Type as TypeLabel,
1212
Updatable,
1313
} from '../nls';
1414

@@ -66,6 +66,11 @@ export namespace LibrarySearch {
6666
'Retired',
6767
] as const;
6868
export type Type = typeof TypeLiterals[number];
69+
export namespace Type {
70+
export function is(arg: unknown): arg is Type {
71+
return typeof arg === 'string' && TypeLiterals.includes(arg as Type);
72+
}
73+
}
6974
export const TypeLabels: Record<Type, string> = {
7075
All: All,
7176
Updatable: Updatable,
@@ -90,6 +95,11 @@ export namespace LibrarySearch {
9095
'Uncategorized',
9196
] as const;
9297
export type Topic = typeof TopicLiterals[number];
98+
export namespace Topic {
99+
export function is(arg: unknown): arg is Topic {
100+
return typeof arg === 'string' && TopicLiterals.includes(arg as Topic);
101+
}
102+
}
93103
export const TopicLabels: Record<Topic, string> = {
94104
All: All,
95105
Communication: nls.localize(
@@ -126,7 +136,7 @@ export namespace LibrarySearch {
126136
string
127137
> = {
128138
topic: nls.localize('arduino/librarySearchProperty/topic', 'Topic'),
129-
type: Type,
139+
type: TypeLabel,
130140
};
131141
}
132142

0 commit comments

Comments
 (0)