mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-09 04:16:38 +00:00
Use service to load sketches
Signed-off-by: jbicker <jan.bicker@typefox.io>
This commit is contained in:
parent
0c937212e2
commit
9d3cbf2ea0
@ -2,7 +2,8 @@ import { injectable, inject } from "inversify";
|
||||
import { MenuContribution, MenuModelRegistry, MenuPath, CommandRegistry, Command } from "@theia/core";
|
||||
import { CommonMenus } from "@theia/core/lib/browser";
|
||||
import { ArduinoCommands } from "./arduino-commands";
|
||||
import URI from "@theia/core/lib/common/uri";
|
||||
import { SketchesService, Sketch } from "../common/protocol/sketches-service";
|
||||
import { AWorkspaceService } from "./arduino-workspace-service";
|
||||
|
||||
export namespace ArduinoOpenSketchContextMenu {
|
||||
export const PATH: MenuPath = ['arduino-open-sketch-context-menu'];
|
||||
@ -11,29 +12,46 @@ export namespace ArduinoOpenSketchContextMenu {
|
||||
export const EXAMPLE_SKETCHES_GROUP: MenuPath = [...PATH, '3_examples'];
|
||||
}
|
||||
|
||||
export interface SketchMenuEntry {
|
||||
name: string,
|
||||
uri: URI
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commands: CommandRegistry;
|
||||
|
||||
@inject(SketchesService)
|
||||
protected readonly sketches: SketchesService;
|
||||
|
||||
protected async getWorkspaceSketches(): Promise<SketchMenuEntry[]> {
|
||||
return [
|
||||
{
|
||||
name: 'foo',
|
||||
uri: new URI('this/is/a/test/uri/foo')
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
uri: new URI('this/is/a/test/uri/bar')
|
||||
constructor(
|
||||
@inject(AWorkspaceService) protected readonly workspaceService: AWorkspaceService,
|
||||
@inject(MenuModelRegistry) protected readonly menuRegistry: MenuModelRegistry) {
|
||||
workspaceService.onWorkspaceChanged(() => {
|
||||
if (this.workspaceService.workspace) {
|
||||
this.registerSketchesInMenu(menuRegistry);
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
protected registerSketchesInMenu(registry: MenuModelRegistry) {
|
||||
this.getWorkspaceSketches().then(sketches => {
|
||||
sketches.forEach(sketch => {
|
||||
const command: Command = {
|
||||
id: 'openSketch' + sketch.name
|
||||
}
|
||||
this.commands.registerCommand(command, {
|
||||
execute: () => this.commands.executeCommand(ArduinoCommands.OPEN_SKETCH.id, sketch)
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoOpenSketchContextMenu.WS_SKETCHES_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
protected async getWorkspaceSketches(): Promise<Sketch[]> {
|
||||
const sketches = this.sketches.getSketches(this.workspaceService.workspace);
|
||||
return sketches;
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry) {
|
||||
@ -45,23 +63,5 @@ export class ArduinoFileMenuContribution implements MenuContribution {
|
||||
commandId: ArduinoCommands.OPEN_FILE_NAVIGATOR.id,
|
||||
label: 'Open...'
|
||||
});
|
||||
|
||||
this.getWorkspaceSketches().then(sketches => {
|
||||
sketches.forEach(sketch => {
|
||||
|
||||
const command: Command = {
|
||||
id: 'openSketch' + sketch.name
|
||||
}
|
||||
this.commands.registerCommand(command, {
|
||||
execute: () => this.commands.executeCommand(ArduinoCommands.OPEN_SKETCH.id, sketch)
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoOpenSketchContextMenu.WS_SKETCHES_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
}
|
@ -24,7 +24,9 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { open, ContextMenuRenderer, OpenerService, Widget } from '@theia/core/lib/browser';
|
||||
import { OpenFileDialogProps, FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import { ArduinoOpenSketchContextMenu, SketchMenuEntry } from './arduino-file-menu';
|
||||
import { ArduinoOpenSketchContextMenu } from './arduino-file-menu';
|
||||
import { Sketch, SketchesService } from '../common/protocol/sketches-service';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendContribution extends DefaultFrontendApplicationContribution implements TabBarToolbarContribution, CommandContribution {
|
||||
@ -68,15 +70,22 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
||||
@inject(ContextMenuRenderer)
|
||||
protected readonly contextMenuRenderer: ContextMenuRenderer;
|
||||
|
||||
@inject(FileDialogService)
|
||||
@inject(FileDialogService)
|
||||
protected readonly fileDialogService: FileDialogService;
|
||||
|
||||
@inject(FileSystem)
|
||||
@inject(FileSystem)
|
||||
protected readonly fileSystem: FileSystem;
|
||||
|
||||
@inject(OpenerService)
|
||||
@inject(OpenerService)
|
||||
protected readonly openerService: OpenerService;
|
||||
|
||||
@inject(SketchesService)
|
||||
protected readonly sketches: SketchesService;
|
||||
|
||||
@inject(WindowService)
|
||||
protected readonly windowService: WindowService;
|
||||
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
// This is a hack. Otherwise, the backend services won't bind.
|
||||
@ -165,7 +174,7 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
||||
isEnabled: widget => this.isArduinoToolbar(widget),
|
||||
execute: async (widget: Widget, event: React.MouseEvent<HTMLElement>) => {
|
||||
const el = (event.target as HTMLElement).parentElement;
|
||||
if(el) {
|
||||
if (el) {
|
||||
this.contextMenuRenderer.render(ArduinoOpenSketchContextMenu.PATH, {
|
||||
x: el.getBoundingClientRect().left,
|
||||
y: el.getBoundingClientRect().top + el.offsetHeight
|
||||
@ -179,8 +188,24 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
||||
})
|
||||
registry.registerCommand(ArduinoCommands.OPEN_SKETCH, {
|
||||
isEnabled: () => true,
|
||||
execute: (sketch: SketchMenuEntry) => {
|
||||
console.log("OPEN SOME SKETCH", sketch);
|
||||
execute: async (sketch: Sketch) => {
|
||||
// const url = new URL(window.location.href);
|
||||
// if (this.workspaceService.workspace) {
|
||||
// const wsUri = this.workspaceService.workspace.uri;
|
||||
// const path = new URI(wsUri).path;
|
||||
// url.hash = path + '?sketch=' + sketch.name
|
||||
// }
|
||||
// this.windowService.openNewWindow(url.toString());
|
||||
|
||||
const fileStat = await this.fileSystem.getFileStat(sketch.uri);
|
||||
if (fileStat) {
|
||||
const sketchFiles = await this.sketches.getSketchFiles(fileStat);
|
||||
sketchFiles.forEach(sketchFile => {
|
||||
const uri = new URI(sketchFile);
|
||||
this.editorManager.open(uri);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
registry.registerCommand(ArduinoCommands.NEW_SKETCH, new WorkspaceRootUriAwareCommandHandler(this.workspaceService, this.selectionService, {
|
||||
|
@ -12,6 +12,7 @@ import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
|
||||
import { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
|
||||
import { LibraryListWidgetFrontendContribution } from './library/list-widget-frontend-contribution';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { BoardsListWidget } from './boards/boards-list-widget';
|
||||
@ -70,6 +71,9 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
||||
}));
|
||||
bind(FrontendApplicationContribution).toService(LibraryListWidgetFrontendContribution);
|
||||
|
||||
// Sketch list service
|
||||
bind(SketchesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, SketchesServicePath)).inSingletonScope();
|
||||
|
||||
// Boards Notification service for updating boards list
|
||||
// TODO (post-PoC): move this to boards service/backend
|
||||
bind(BoardsNotificationService).toSelf().inSingletonScope();
|
||||
@ -106,9 +110,11 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
||||
container.get(CoreService);
|
||||
container.get(LibraryService);
|
||||
container.get(BoardsService);
|
||||
container.get(SketchesService);
|
||||
return workspaceServiceExt;
|
||||
});
|
||||
|
||||
bind(AWorkspaceService).toSelf().inSingletonScope();
|
||||
rebind(WorkspaceService).to(AWorkspaceService).inSingletonScope();
|
||||
bind(SketchFactory).toSelf().inSingletonScope();
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
import { FileStat } from "@theia/filesystem/lib/common";
|
||||
|
||||
export const SketchesServicePath = '/services/sketches-service';
|
||||
export const SketchesService = Symbol('SketchesService');
|
||||
export interface SketchesService {
|
||||
getSketches(fileStat?: FileStat): Promise<Sketch[]>
|
||||
getSketchFiles(fileStat: FileStat): Promise<string[]>
|
||||
}
|
||||
|
||||
export interface Sketch {
|
||||
name: string;
|
||||
uri: string
|
||||
}
|
@ -17,6 +17,8 @@ import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core';
|
||||
import { ToolOutputServiceServerImpl } from './tool-output-service-impl';
|
||||
import { DefaultWorkspaceServerExt } from './default-workspace-server-ext';
|
||||
import { WorkspaceServer } from '@theia/workspace/lib/common';
|
||||
import { SketchesServiceImpl } from './sketches-service-impl';
|
||||
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
||||
@ -30,6 +32,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(libraryServiceConnectionModule);
|
||||
|
||||
// Sketches service
|
||||
const sketchesServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(SketchesServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SketchesService).toService(SketchesServiceImpl);
|
||||
bindBackendService(SketchesServicePath, SketchesService);
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(sketchesServiceConnectionModule);
|
||||
|
||||
// Boards service
|
||||
const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(BoardsServiceImpl).toSelf().inSingletonScope();
|
||||
|
67
arduino-ide-extension/src/node/sketches-service-impl.ts
Normal file
67
arduino-ide-extension/src/node/sketches-service-impl.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { injectable } from "inversify";
|
||||
import { SketchesService, Sketch } from "../common/protocol/sketches-service";
|
||||
import URI from "@theia/core/lib/common/uri";
|
||||
import { FileStat } from "@theia/filesystem/lib/common";
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export const ALLOWED_FILE_EXTENSIONS = [".c", ".cpp", ".h", ".hh", ".hpp", ".s", ".pde", ".ino"];
|
||||
|
||||
@injectable()
|
||||
export class SketchesServiceImpl implements SketchesService {
|
||||
|
||||
async getSketches(fileStat?: FileStat): Promise<Sketch[]> {
|
||||
const sketches: Sketch[] = [];
|
||||
if (fileStat && fileStat.isDirectory) {
|
||||
const sketchFolderPath = this.getPath(fileStat);
|
||||
const files = fs.readdirSync(sketchFolderPath);
|
||||
files.forEach(file => {
|
||||
const filePath = path.join(sketchFolderPath, file);
|
||||
if (this.isSketchFolder(filePath, file)) {
|
||||
sketches.push({
|
||||
name: file,
|
||||
uri: filePath
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return sketches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all allowed files.
|
||||
* File extensions: "c", "cpp", "h", "hh", "hpp", "s", "pde", "ino"
|
||||
*/
|
||||
async getSketchFiles(sketchDir: FileStat): Promise<string[]> {
|
||||
const files: string[] = [];
|
||||
const sketchDirPath = this.getPath(sketchDir);
|
||||
const sketchDirContents = fs.readdirSync(sketchDirPath);
|
||||
sketchDirContents.forEach(fileName => {
|
||||
const filePath = path.join(sketchDirPath, fileName);
|
||||
if (fs.existsSync(filePath) &&
|
||||
fs.lstatSync(filePath).isFile() &&
|
||||
ALLOWED_FILE_EXTENSIONS.indexOf(path.extname(filePath)) !== -1) {
|
||||
files.push(filePath);
|
||||
}
|
||||
});
|
||||
return files;
|
||||
}
|
||||
|
||||
protected isSketchFolder(path: string, name: string): boolean {
|
||||
if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) {
|
||||
const files = fs.readdirSync(path);
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (files[i] === name + '.ino') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected getPath(fileStat: FileStat) {
|
||||
const fileStatUri = fileStat.uri;
|
||||
const uri = new URI(fileStatUri);
|
||||
return uri.path.toString();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user