mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-22 16:46:09 +00:00
ATL-73: Added library examples to the app.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
@@ -2,9 +2,12 @@ import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { join, basename } from 'path';
|
||||
import * as fs from './fs-extra';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { Sketch } from '../common/protocol/sketches-service';
|
||||
import { SketchesServiceImpl } from './sketches-service-impl';
|
||||
import { ExamplesService, ExampleContainer } from '../common/protocol/examples-service';
|
||||
import { LibraryServiceServer, LibraryLocation, LibraryPackage } from '../common/protocol';
|
||||
import { ConfigServiceImpl } from './config-service-impl';
|
||||
|
||||
@injectable()
|
||||
export class ExamplesServiceImpl implements ExamplesService {
|
||||
@@ -12,22 +15,100 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
@inject(SketchesServiceImpl)
|
||||
protected readonly sketchesService: SketchesServiceImpl;
|
||||
|
||||
protected _all: ExampleContainer | undefined;
|
||||
@inject(LibraryServiceServer)
|
||||
protected readonly libraryService: LibraryServiceServer;
|
||||
|
||||
@inject(ConfigServiceImpl)
|
||||
protected readonly configService: ConfigServiceImpl;
|
||||
|
||||
protected _all: ExampleContainer[] | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.all();
|
||||
this.builtIns();
|
||||
}
|
||||
|
||||
async all(): Promise<ExampleContainer> {
|
||||
async builtIns(): Promise<ExampleContainer[]> {
|
||||
if (this._all) {
|
||||
return this._all;
|
||||
}
|
||||
this._all = await this.load();
|
||||
const exampleRootPath = join(__dirname, '..', '..', 'Examples');
|
||||
const exampleNames = await fs.readdir(exampleRootPath);
|
||||
this._all = await Promise.all(exampleNames.map(name => join(exampleRootPath, name)).map(path => this.load(path)));
|
||||
return this._all;
|
||||
}
|
||||
|
||||
protected async load(path: string = join(__dirname, '..', '..', 'Examples')): Promise<ExampleContainer> {
|
||||
// TODO: decide whether it makes sense to cache them. Keys should be: `fqbn` + version of containing core/library.
|
||||
async installed({ fqbn }: { fqbn: string }): Promise<{ user: ExampleContainer[], current: ExampleContainer[], any: ExampleContainer[] }> {
|
||||
const user: ExampleContainer[] = [];
|
||||
const current: ExampleContainer[] = [];
|
||||
const any: ExampleContainer[] = [];
|
||||
if (fqbn) {
|
||||
const packages = await this.libraryService.list({ fqbn });
|
||||
for (const pkg of packages) {
|
||||
const container = await this.tryGroupExamples(pkg);
|
||||
const { location } = pkg;
|
||||
if (location === LibraryLocation.USER) {
|
||||
user.push(container);
|
||||
} else if (location === LibraryLocation.PLATFORM_BUILTIN || LibraryLocation.REFERENCED_PLATFORM_BUILTIN) {
|
||||
current.push(container);
|
||||
} else {
|
||||
any.push(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { user, current, any };
|
||||
}
|
||||
|
||||
/**
|
||||
* The CLI provides direct FS paths to the examples so that menus and menu groups cannot be built for the UI by traversing the
|
||||
* folder hierarchy. This method tries to workaround it by falling back to the `installDirUri` and manually creating the
|
||||
* location of the examples. Otherwise it creates the example container from the direct examples FS paths.
|
||||
*/
|
||||
protected async tryGroupExamples({ label, exampleUris, installDirUri }: LibraryPackage): Promise<ExampleContainer> {
|
||||
const paths = exampleUris.map(uri => FileUri.fsPath(uri));
|
||||
if (installDirUri) {
|
||||
for (const example of ['example', 'Example', 'EXAMPLE', 'examples', 'Examples', 'EXAMPLES']) {
|
||||
const examplesPath = join(FileUri.fsPath(installDirUri), example);
|
||||
const exists = await fs.exists(examplesPath);
|
||||
const isDir = exists && (await fs.lstat(examplesPath)).isDirectory();
|
||||
if (isDir) {
|
||||
const fileNames = await fs.readdir(examplesPath);
|
||||
const children: ExampleContainer[] = [];
|
||||
const sketches: Sketch[] = [];
|
||||
for (const fileName of fileNames) {
|
||||
const subPath = join(examplesPath, fileName);
|
||||
const subIsDir = (await fs.lstat(subPath)).isDirectory();
|
||||
if (subIsDir) {
|
||||
const sketch = await this.tryLoadSketch(subPath);
|
||||
if (!sketch) {
|
||||
const container = await this.load(subPath);
|
||||
if (container.children.length || container.sketches.length) {
|
||||
children.push(container);
|
||||
}
|
||||
} else {
|
||||
sketches.push(sketch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
label,
|
||||
children,
|
||||
sketches
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
const sketches = await Promise.all(paths.map(path => this.tryLoadSketch(path)));
|
||||
return {
|
||||
label,
|
||||
children: [],
|
||||
sketches: sketches.filter(notEmpty)
|
||||
};
|
||||
}
|
||||
|
||||
// Built-ins are included inside the IDE.
|
||||
protected async load(path: string): Promise<ExampleContainer> {
|
||||
if (!await fs.exists(path)) {
|
||||
throw new Error('Examples are not available');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user