mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-17 06:09:28 +00:00
chopped up the FE contribution
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry } from './contribution';
|
||||
import { SaveAsSketch } from './save-as-sketch';
|
||||
|
||||
@injectable()
|
||||
export class CloseSketch extends SketchContribution {
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(CloseSketch.Commands.CLOSE_SKETCH, {
|
||||
execute: async () => {
|
||||
const sketch = await this.getCurrentSketch();
|
||||
if (!sketch) {
|
||||
return;
|
||||
}
|
||||
const isTemp = await this.sketchService.isTemp(sketch);
|
||||
if (isTemp) {
|
||||
await this.commandService.executeCommand(SaveAsSketch.Commands.SAVE_AS_SKETCH.id, { openAfterMove: false, execOnlyIfTemp: true });
|
||||
await this.commandService.executeCommand(WorkspaceCommands.CLOSE.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, {
|
||||
commandId: CloseSketch.Commands.CLOSE_SKETCH.id,
|
||||
label: 'Close',
|
||||
order: '5'
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({
|
||||
command: CloseSketch.Commands.CLOSE_SKETCH.id,
|
||||
keybinding: 'CtrlCmd+W' // TODO: Windows binding?
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace CloseSketch {
|
||||
export namespace Commands {
|
||||
export const CLOSE_SKETCH: Command = {
|
||||
id: 'arduino-close-sketch'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { inject, injectable, interfaces } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { MenuModelRegistry, MenuContribution } from '@theia/core/lib/common/menu';
|
||||
import { KeybindingRegistry, KeybindingContribution } from '@theia/core/lib/browser/keybinding';
|
||||
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { Command, CommandRegistry, CommandContribution, CommandService } from '@theia/core/lib/common/command';
|
||||
import { SketchesService, ConfigService, FileSystemExt, Sketch } from '../../common/protocol';
|
||||
|
||||
export { Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry, URI, Sketch };
|
||||
|
||||
@injectable()
|
||||
export abstract class Contribution implements CommandContribution, MenuContribution, KeybindingContribution, TabBarToolbarContribution {
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
@inject(CommandService)
|
||||
protected readonly commandService: CommandService;
|
||||
|
||||
@inject(WorkspaceService)
|
||||
protected readonly workspaceService: WorkspaceService;
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export abstract class SketchContribution extends Contribution {
|
||||
|
||||
@inject(FileSystem)
|
||||
protected readonly fileSystem: FileSystem;
|
||||
|
||||
@inject(FileSystemExt)
|
||||
protected readonly fileSystemExt: FileSystemExt;
|
||||
|
||||
@inject(ConfigService)
|
||||
protected readonly configService: ConfigService;
|
||||
|
||||
@inject(SketchesService)
|
||||
protected readonly sketchService: SketchesService;
|
||||
|
||||
protected async getCurrentSketch(): Promise<Sketch | undefined> {
|
||||
const sketches = (await Promise.all(this.workspaceService.tryGetRoots().map(({ uri }) => this.sketchService.getSketchFolder(uri)))).filter(notEmpty);
|
||||
if (!sketches.length) {
|
||||
return;
|
||||
}
|
||||
if (sketches.length > 1) {
|
||||
console.log(`Multiple sketch folders were found in the workspace. Falling back to the first one. Sketch folders: ${JSON.stringify(sketches)}`);
|
||||
}
|
||||
return sketches[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace Contribution {
|
||||
export function configure<T>(bind: interfaces.Bind, serviceIdentifier: interfaces.ServiceIdentifier<T>): void {
|
||||
bind(serviceIdentifier).toSelf().inSingletonScope();
|
||||
bind(CommandContribution).toService(serviceIdentifier);
|
||||
bind(MenuContribution).toService(serviceIdentifier);
|
||||
bind(KeybindingContribution).toService(serviceIdentifier);
|
||||
bind(TabBarToolbarContribution).toService(serviceIdentifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { SketchContribution, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class NewSketch extends SketchContribution {
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(NewSketch.Commands.NEW_SKETCH, {
|
||||
execute: () => this.newSketch()
|
||||
});
|
||||
registry.registerCommand(NewSketch.Commands.NEW_SKETCH__TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
execute: () => registry.executeCommand(NewSketch.Commands.NEW_SKETCH.id)
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, {
|
||||
commandId: NewSketch.Commands.NEW_SKETCH.id,
|
||||
label: 'New',
|
||||
order: '0'
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({
|
||||
command: NewSketch.Commands.NEW_SKETCH.id,
|
||||
keybinding: 'CtrlCmd+N'
|
||||
});
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
registry.registerItem({
|
||||
id: NewSketch.Commands.NEW_SKETCH__TOOLBAR.id,
|
||||
command: NewSketch.Commands.NEW_SKETCH__TOOLBAR.id,
|
||||
tooltip: 'New',
|
||||
priority: 4
|
||||
});
|
||||
}
|
||||
|
||||
async newSketch(): Promise<void> {
|
||||
try {
|
||||
const sketch = await this.sketchService.createNewSketch();
|
||||
this.workspaceService.open(new URI(sketch.uri));
|
||||
} catch (e) {
|
||||
await this.messageService.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace NewSketch {
|
||||
export namespace Commands {
|
||||
export const NEW_SKETCH: Command = {
|
||||
id: 'arduino-new-sketch'
|
||||
};
|
||||
export const NEW_SKETCH__TOOLBAR: Command = {
|
||||
id: 'arduino-new-sketch--toolbar'
|
||||
};
|
||||
}
|
||||
}
|
||||
134
arduino-ide-extension/src/browser/contributions/open-sketch.ts
Normal file
134
arduino-ide-extension/src/browser/contributions/open-sketch.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { remote } from 'electron';
|
||||
import { Disposable } from '@theia/languages/lib/browser';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Widget, ContextMenuRenderer } from '@theia/core/lib/browser';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { SketchContribution, Sketch, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class OpenSketch extends SketchContribution {
|
||||
|
||||
@inject(MenuModelRegistry)
|
||||
protected readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(ContextMenuRenderer)
|
||||
protected readonly contextMenuRenderer: ContextMenuRenderer;
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH, {
|
||||
execute: arg => Sketch.is(arg) ? this.openSketch(arg) : this.openSketch()
|
||||
});
|
||||
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH__TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
execute: async (_: Widget, target: EventTarget) => {
|
||||
const sketches = await this.sketchService.getSketches();
|
||||
if (!sketches.length) {
|
||||
this.openSketch();
|
||||
} else {
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
const toDisposeOnClose = new DisposableCollection();
|
||||
this.menuRegistry.registerMenuAction(ArduinoMenus.OPEN_SKETCH__CONTEXT__OPEN_GROUP, {
|
||||
commandId: OpenSketch.Commands.OPEN_SKETCH.id,
|
||||
label: 'Open...'
|
||||
});
|
||||
toDisposeOnClose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(OpenSketch.Commands.OPEN_SKETCH)));
|
||||
for (const sketch of sketches) {
|
||||
const command = { id: `arduino-open-sketch--${sketch.uri}` };
|
||||
const handler = { execute: () => this.openSketch(sketch) };
|
||||
toDisposeOnClose.push(registry.registerCommand(command, handler));
|
||||
this.menuRegistry.registerMenuAction(ArduinoMenus.OPEN_SKETCH__CONTEXT__RECENT_GROUP, {
|
||||
commandId: command.id,
|
||||
label: sketch.name
|
||||
});
|
||||
toDisposeOnClose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
|
||||
}
|
||||
const { parentElement } = target;
|
||||
if (parentElement) {
|
||||
const options = {
|
||||
menuPath: ArduinoMenus.OPEN_SKETCH__CONTEXT,
|
||||
anchor: {
|
||||
x: parentElement.getBoundingClientRect().left,
|
||||
y: parentElement.getBoundingClientRect().top + parentElement.offsetHeight
|
||||
},
|
||||
onHide: () => toDisposeOnClose.dispose()
|
||||
}
|
||||
this.contextMenuRenderer.render(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, {
|
||||
commandId: OpenSketch.Commands.OPEN_SKETCH.id,
|
||||
label: 'Open...',
|
||||
order: '1'
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({
|
||||
command: OpenSketch.Commands.OPEN_SKETCH.id,
|
||||
keybinding: 'CtrlCmd+O'
|
||||
});
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
registry.registerItem({
|
||||
id: OpenSketch.Commands.OPEN_SKETCH__TOOLBAR.id,
|
||||
command: OpenSketch.Commands.OPEN_SKETCH__TOOLBAR.id,
|
||||
tooltip: 'Open',
|
||||
priority: 5
|
||||
});
|
||||
}
|
||||
|
||||
async openSketch(toOpen: MaybePromise<Sketch | undefined> = this.selectSketch()): Promise<void> {
|
||||
const sketch = await toOpen;
|
||||
if (sketch) {
|
||||
this.workspaceService.open(new URI(sketch.uri));
|
||||
}
|
||||
}
|
||||
|
||||
protected async selectSketch(): Promise<Sketch | undefined> {
|
||||
const config = await this.configService.getConfiguration();
|
||||
const defaultPath = await this.fileSystem.getFsPath(config.sketchDirUri);
|
||||
const { filePaths } = await remote.dialog.showOpenDialog({
|
||||
defaultPath,
|
||||
properties: ['createDirectory', 'openFile'],
|
||||
filters: [
|
||||
{
|
||||
name: 'Sketch',
|
||||
extensions: ['ino']
|
||||
}
|
||||
]
|
||||
});
|
||||
if (!filePaths.length) {
|
||||
return undefined;
|
||||
}
|
||||
if (filePaths.length > 1) {
|
||||
this.logger.warn(`Multiple sketches were selected: ${filePaths}. Using the first one.`);
|
||||
}
|
||||
// TODO: validate sketch file name against the sketch folder. Move the file if required.
|
||||
const sketchFilePath = filePaths[0];
|
||||
const sketchFileUri = await this.fileSystemExt.getUri(sketchFilePath);
|
||||
return this.sketchService.getSketchFolder(sketchFileUri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace OpenSketch {
|
||||
export namespace Commands {
|
||||
export const OPEN_SKETCH: Command = {
|
||||
id: 'arduino-open-sketch'
|
||||
};
|
||||
export const OPEN_SKETCH__TOOLBAR: Command = {
|
||||
id: 'arduino-open-sketch--toolbar'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { remote } from 'electron';
|
||||
import * as dateFormat from 'dateformat';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { SketchContribution, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class SaveAsSketch extends SketchContribution {
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(SaveAsSketch.Commands.SAVE_AS_SKETCH, {
|
||||
execute: args => this.saveAs(args)
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, {
|
||||
commandId: SaveAsSketch.Commands.SAVE_AS_SKETCH.id,
|
||||
label: 'Save As...',
|
||||
order: '7'
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({
|
||||
command: SaveAsSketch.Commands.SAVE_AS_SKETCH.id,
|
||||
keybinding: 'CtrlCmd+Shift+S'
|
||||
});
|
||||
}
|
||||
|
||||
async saveAs({ execOnlyIfTemp, openAfterMove }: SaveAsSketch.Options = SaveAsSketch.Options.DEFAULT): Promise<void> {
|
||||
const sketch = await this.getCurrentSketch();
|
||||
if (!sketch) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isTemp = await this.sketchService.isTemp(sketch);
|
||||
if (!isTemp && !!execOnlyIfTemp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If target does not exist, propose a `directories.user`/${sketch.name} path
|
||||
// If target exists, propose `directories.user`/${sketch.name}_copy_${yyyymmddHHMMss}
|
||||
const sketchDirUri = new URI((await this.configService.getConfiguration()).sketchDirUri);
|
||||
const exists = await this.fileSystem.exists(sketchDirUri.resolve(sketch.name).toString());
|
||||
const defaultUri = exists
|
||||
? sketchDirUri.resolve(sketchDirUri.resolve(`${sketch.name}_copy_${dateFormat(new Date(), 'yyyymmddHHMMss')}`).toString())
|
||||
: sketchDirUri.resolve(sketch.name);
|
||||
const defaultPath = await this.fileSystem.getFsPath(defaultUri.toString())!;
|
||||
const { filePath, canceled } = await remote.dialog.showSaveDialog({ title: 'Save sketch folder as...', defaultPath });
|
||||
if (!filePath || canceled) {
|
||||
return;
|
||||
}
|
||||
const destinationUri = await this.fileSystemExt.getUri(filePath);
|
||||
if (!destinationUri) {
|
||||
return;
|
||||
}
|
||||
const workspaceUri = await this.sketchService.copy(sketch, { destinationUri });
|
||||
if (workspaceUri && openAfterMove) {
|
||||
this.workspaceService.open(new URI(workspaceUri));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace SaveAsSketch {
|
||||
export namespace Commands {
|
||||
export const SAVE_AS_SKETCH: Command = {
|
||||
id: 'arduino-save-as-sketch'
|
||||
};
|
||||
}
|
||||
export interface Options {
|
||||
readonly execOnlyIfTemp?: boolean;
|
||||
readonly openAfterMove?: boolean;
|
||||
}
|
||||
export namespace Options {
|
||||
export const DEFAULT: Options = {
|
||||
execOnlyIfTemp: false,
|
||||
openAfterMove: true
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class SaveSketch extends SketchContribution {
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(SaveSketch.Commands.SAVE_SKETCH, {
|
||||
execute: () => this.saveSketch()
|
||||
});
|
||||
registry.registerCommand(SaveSketch.Commands.SAVE_SKETCH__TOOLBAR, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
execute: () => registry.executeCommand(SaveSketch.Commands.SAVE_SKETCH.id)
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, {
|
||||
commandId: SaveSketch.Commands.SAVE_SKETCH.id,
|
||||
label: 'Save',
|
||||
order: '6'
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(registry: KeybindingRegistry): void {
|
||||
registry.registerKeybinding({
|
||||
command: SaveSketch.Commands.SAVE_SKETCH.id,
|
||||
keybinding: 'CtrlCmd+S'
|
||||
});
|
||||
}
|
||||
|
||||
registerToolbarItems(registry: TabBarToolbarRegistry): void {
|
||||
registry.registerItem({
|
||||
id: SaveSketch.Commands.SAVE_SKETCH__TOOLBAR.id,
|
||||
command: SaveSketch.Commands.SAVE_SKETCH__TOOLBAR.id,
|
||||
tooltip: 'Save',
|
||||
priority: 6
|
||||
});
|
||||
}
|
||||
|
||||
async saveSketch(): Promise<void> {
|
||||
return this.commandService.executeCommand(CommonCommands.SAVE_ALL.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export namespace SaveSketch {
|
||||
export namespace Commands {
|
||||
export const SAVE_SKETCH: Command = {
|
||||
id: 'arduino-save-sketch'
|
||||
};
|
||||
export const SAVE_SKETCH__TOOLBAR: Command = {
|
||||
id: 'arduino-save-sketch--toolbar'
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user