mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-09 20:36:32 +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 { MenuContribution, MenuModelRegistry, MenuPath, CommandRegistry, Command } from "@theia/core";
|
||||||
import { CommonMenus } from "@theia/core/lib/browser";
|
import { CommonMenus } from "@theia/core/lib/browser";
|
||||||
import { ArduinoCommands } from "./arduino-commands";
|
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 namespace ArduinoOpenSketchContextMenu {
|
||||||
export const PATH: MenuPath = ['arduino-open-sketch-context-menu'];
|
export const PATH: MenuPath = ['arduino-open-sketch-context-menu'];
|
||||||
@ -11,44 +12,28 @@ export namespace ArduinoOpenSketchContextMenu {
|
|||||||
export const EXAMPLE_SKETCHES_GROUP: MenuPath = [...PATH, '3_examples'];
|
export const EXAMPLE_SKETCHES_GROUP: MenuPath = [...PATH, '3_examples'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SketchMenuEntry {
|
|
||||||
name: string,
|
|
||||||
uri: URI
|
|
||||||
}
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class ArduinoFileMenuContribution implements MenuContribution {
|
export class ArduinoFileMenuContribution implements MenuContribution {
|
||||||
|
|
||||||
@inject(CommandRegistry)
|
@inject(CommandRegistry)
|
||||||
protected readonly commands: CommandRegistry;
|
protected readonly commands: CommandRegistry;
|
||||||
|
|
||||||
|
@inject(SketchesService)
|
||||||
|
protected readonly sketches: SketchesService;
|
||||||
|
|
||||||
protected async getWorkspaceSketches(): Promise<SketchMenuEntry[]> {
|
constructor(
|
||||||
return [
|
@inject(AWorkspaceService) protected readonly workspaceService: AWorkspaceService,
|
||||||
{
|
@inject(MenuModelRegistry) protected readonly menuRegistry: MenuModelRegistry) {
|
||||||
name: 'foo',
|
workspaceService.onWorkspaceChanged(() => {
|
||||||
uri: new URI('this/is/a/test/uri/foo')
|
if (this.workspaceService.workspace) {
|
||||||
},
|
this.registerSketchesInMenu(menuRegistry);
|
||||||
{
|
|
||||||
name: 'bar',
|
|
||||||
uri: new URI('this/is/a/test/uri/bar')
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
registerMenus(registry: MenuModelRegistry) {
|
|
||||||
registry.registerMenuAction([...CommonMenus.FILE, '0_new_sletch'], {
|
|
||||||
commandId: ArduinoCommands.NEW_SKETCH.id
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
registry.registerMenuAction(ArduinoOpenSketchContextMenu.OPEN_GROUP, {
|
protected registerSketchesInMenu(registry: MenuModelRegistry) {
|
||||||
commandId: ArduinoCommands.OPEN_FILE_NAVIGATOR.id,
|
|
||||||
label: 'Open...'
|
|
||||||
});
|
|
||||||
|
|
||||||
this.getWorkspaceSketches().then(sketches => {
|
this.getWorkspaceSketches().then(sketches => {
|
||||||
sketches.forEach(sketch => {
|
sketches.forEach(sketch => {
|
||||||
|
|
||||||
const command: Command = {
|
const command: Command = {
|
||||||
id: 'openSketch' + sketch.name
|
id: 'openSketch' + sketch.name
|
||||||
}
|
}
|
||||||
@ -62,6 +47,21 @@ export class ArduinoFileMenuContribution implements MenuContribution {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async getWorkspaceSketches(): Promise<Sketch[]> {
|
||||||
|
const sketches = this.sketches.getSketches(this.workspaceService.workspace);
|
||||||
|
return sketches;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerMenus(registry: MenuModelRegistry) {
|
||||||
|
registry.registerMenuAction([...CommonMenus.FILE, '0_new_sletch'], {
|
||||||
|
commandId: ArduinoCommands.NEW_SKETCH.id
|
||||||
|
})
|
||||||
|
|
||||||
|
registry.registerMenuAction(ArduinoOpenSketchContextMenu.OPEN_GROUP, {
|
||||||
|
commandId: ArduinoCommands.OPEN_FILE_NAVIGATOR.id,
|
||||||
|
label: 'Open...'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,7 +24,9 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
|||||||
import { open, ContextMenuRenderer, OpenerService, Widget } from '@theia/core/lib/browser';
|
import { open, ContextMenuRenderer, OpenerService, Widget } from '@theia/core/lib/browser';
|
||||||
import { OpenFileDialogProps, FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
|
import { OpenFileDialogProps, FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
|
||||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
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()
|
@injectable()
|
||||||
export class ArduinoFrontendContribution extends DefaultFrontendApplicationContribution implements TabBarToolbarContribution, CommandContribution {
|
export class ArduinoFrontendContribution extends DefaultFrontendApplicationContribution implements TabBarToolbarContribution, CommandContribution {
|
||||||
@ -77,6 +79,13 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
|||||||
@inject(OpenerService)
|
@inject(OpenerService)
|
||||||
protected readonly openerService: OpenerService;
|
protected readonly openerService: OpenerService;
|
||||||
|
|
||||||
|
@inject(SketchesService)
|
||||||
|
protected readonly sketches: SketchesService;
|
||||||
|
|
||||||
|
@inject(WindowService)
|
||||||
|
protected readonly windowService: WindowService;
|
||||||
|
|
||||||
|
|
||||||
@postConstruct()
|
@postConstruct()
|
||||||
protected async init(): Promise<void> {
|
protected async init(): Promise<void> {
|
||||||
// This is a hack. Otherwise, the backend services won't bind.
|
// 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),
|
isEnabled: widget => this.isArduinoToolbar(widget),
|
||||||
execute: async (widget: Widget, event: React.MouseEvent<HTMLElement>) => {
|
execute: async (widget: Widget, event: React.MouseEvent<HTMLElement>) => {
|
||||||
const el = (event.target as HTMLElement).parentElement;
|
const el = (event.target as HTMLElement).parentElement;
|
||||||
if(el) {
|
if (el) {
|
||||||
this.contextMenuRenderer.render(ArduinoOpenSketchContextMenu.PATH, {
|
this.contextMenuRenderer.render(ArduinoOpenSketchContextMenu.PATH, {
|
||||||
x: el.getBoundingClientRect().left,
|
x: el.getBoundingClientRect().left,
|
||||||
y: el.getBoundingClientRect().top + el.offsetHeight
|
y: el.getBoundingClientRect().top + el.offsetHeight
|
||||||
@ -179,8 +188,24 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
|
|||||||
})
|
})
|
||||||
registry.registerCommand(ArduinoCommands.OPEN_SKETCH, {
|
registry.registerCommand(ArduinoCommands.OPEN_SKETCH, {
|
||||||
isEnabled: () => true,
|
isEnabled: () => true,
|
||||||
execute: (sketch: SketchMenuEntry) => {
|
execute: async (sketch: Sketch) => {
|
||||||
console.log("OPEN SOME 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, {
|
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 { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution';
|
||||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-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 { LibraryListWidgetFrontendContribution } from './library/list-widget-frontend-contribution';
|
||||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||||
import { BoardsListWidget } from './boards/boards-list-widget';
|
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);
|
bind(FrontendApplicationContribution).toService(LibraryListWidgetFrontendContribution);
|
||||||
|
|
||||||
|
// Sketch list service
|
||||||
|
bind(SketchesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, SketchesServicePath)).inSingletonScope();
|
||||||
|
|
||||||
// Boards Notification service for updating boards list
|
// Boards Notification service for updating boards list
|
||||||
// TODO (post-PoC): move this to boards service/backend
|
// TODO (post-PoC): move this to boards service/backend
|
||||||
bind(BoardsNotificationService).toSelf().inSingletonScope();
|
bind(BoardsNotificationService).toSelf().inSingletonScope();
|
||||||
@ -106,9 +110,11 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un
|
|||||||
container.get(CoreService);
|
container.get(CoreService);
|
||||||
container.get(LibraryService);
|
container.get(LibraryService);
|
||||||
container.get(BoardsService);
|
container.get(BoardsService);
|
||||||
|
container.get(SketchesService);
|
||||||
return workspaceServiceExt;
|
return workspaceServiceExt;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bind(AWorkspaceService).toSelf().inSingletonScope();
|
||||||
rebind(WorkspaceService).to(AWorkspaceService).inSingletonScope();
|
rebind(WorkspaceService).to(AWorkspaceService).inSingletonScope();
|
||||||
bind(SketchFactory).toSelf().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 { ToolOutputServiceServerImpl } from './tool-output-service-impl';
|
||||||
import { DefaultWorkspaceServerExt } from './default-workspace-server-ext';
|
import { DefaultWorkspaceServerExt } from './default-workspace-server-ext';
|
||||||
import { WorkspaceServer } from '@theia/workspace/lib/common';
|
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) => {
|
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||||
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
bind(ArduinoDaemon).toSelf().inSingletonScope();
|
||||||
@ -30,6 +32,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
|||||||
});
|
});
|
||||||
bind(ConnectionContainerModule).toConstantValue(libraryServiceConnectionModule);
|
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
|
// Boards service
|
||||||
const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
const boardsServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||||
bind(BoardsServiceImpl).toSelf().inSingletonScope();
|
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