mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-10 06:06:33 +00:00
aligned new file creation to the java ide.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
f503ef0fcf
commit
1f7e06f990
@ -87,7 +87,11 @@ import { BoardsDataMenuUpdater } from './boards/boards-data-menu-updater';
|
||||
import { BoardsDataStore } from './boards/boards-data-store';
|
||||
import { ILogger } from '@theia/core';
|
||||
import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext';
|
||||
import { WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution, FileMenuContribution as TheiaFileMenuContribution } from '@theia/workspace/lib/browser';
|
||||
import {
|
||||
WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution,
|
||||
FileMenuContribution as TheiaFileMenuContribution,
|
||||
WorkspaceCommandContribution as TheiaWorkspaceCommandContribution
|
||||
} from '@theia/workspace/lib/browser';
|
||||
import { WorkspaceFrontendContribution, ArduinoFileMenuContribution } from './theia/workspace/workspace-frontend-contribution';
|
||||
import { Contribution } from './contributions/contribution';
|
||||
import { NewSketch } from './contributions/new-sketch';
|
||||
@ -106,6 +110,7 @@ import { QuitApp } from './contributions/quit-app';
|
||||
import { SketchControl } from './contributions/sketch-control';
|
||||
import { Settings } from './contributions/settings';
|
||||
import { KeybindingRegistry } from './theia/core/keybindings';
|
||||
import { WorkspaceCommandContribution } from './theia/workspace/workspace-commands';
|
||||
|
||||
const ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||
|
||||
@ -283,6 +288,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
rebind(TheiaCommonFrontendContribution).to(CommonFrontendContribution).inSingletonScope();
|
||||
rebind(TheiaPreferencesContribution).to(PreferencesContribution).inSingletonScope();
|
||||
rebind(TheiaKeybindingRegistry).to(KeybindingRegistry).inSingletonScope();
|
||||
rebind(TheiaWorkspaceCommandContribution).to(WorkspaceCommandContribution).inSingletonScope();
|
||||
|
||||
// Show a disconnected status bar, when the daemon is not available
|
||||
bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope();
|
||||
|
@ -0,0 +1,81 @@
|
||||
import { injectable } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { open } from '@theia/core/lib/browser/opener-service';
|
||||
import { FileStat } from '@theia/filesystem/lib/common';
|
||||
import { CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { WorkspaceCommandContribution as TheiaWorkspaceCommandContribution, WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
|
||||
import { Extensions } from '../../../common/protocol';
|
||||
import { WorkspaceInputDialog } from './workspace-input-dialog';
|
||||
|
||||
@injectable()
|
||||
export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribution {
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
super.registerCommands(registry);
|
||||
registry.unregisterCommand(WorkspaceCommands.NEW_FILE);
|
||||
registry.registerCommand(WorkspaceCommands.NEW_FILE, this.newWorkspaceRootUriAwareCommandHandler({
|
||||
execute: uri => this.newFile(uri)
|
||||
}));
|
||||
}
|
||||
|
||||
protected async newFile(uri: URI | undefined): Promise<void> {
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
const parent = await this.getDirectory(uri);
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentUri = new URI(parent.uri);
|
||||
const dialog = new WorkspaceInputDialog({
|
||||
title: 'Name for new file',
|
||||
parentUri,
|
||||
validate: name => this.validateFileName(name, parent, true)
|
||||
}, this.labelProvider);
|
||||
|
||||
const name = await dialog.open();
|
||||
const nameWithExt = this.appendInoExtensionMaybe(name);
|
||||
if (nameWithExt) {
|
||||
const fileUri = parentUri.resolve(nameWithExt);
|
||||
await this.fileSystem.createFile(fileUri.toString());
|
||||
this.fireCreateNewFile({ parent: parentUri, uri: fileUri });
|
||||
open(this.openerService, fileUri);
|
||||
}
|
||||
}
|
||||
|
||||
protected async validateFileName(name: string, parent: FileStat, recursive: boolean = false): Promise<string> {
|
||||
// In the Java IDE the followings are the rules:
|
||||
// - `name` without an extension should default to `name.ino`.
|
||||
// - `name` with a single trailing `.` also defaults to `name.ino`.
|
||||
const nameWithExt = this.appendInoExtensionMaybe(name);
|
||||
const errorMessage = await super.validateFileName(nameWithExt, parent, recursive);
|
||||
if (errorMessage) {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
const extension = nameWithExt.split('.').pop();
|
||||
if (!extension) {
|
||||
return 'Invalid file extension.';
|
||||
}
|
||||
if (Extensions.ALL.indexOf(`.${extension}`) === -1) {
|
||||
return `.${extension} is not a valid extension.`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
protected appendInoExtensionMaybe(name: string | undefined): string {
|
||||
if (!name) {
|
||||
return '';
|
||||
}
|
||||
if (name.trim().length) {
|
||||
if (name.indexOf('.') === -1) {
|
||||
return `${name}.ino`
|
||||
}
|
||||
if (name.indexOf('.') === name.length - 1) {
|
||||
return `${name.slice(0, -1)}.ino`
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { inject } from 'inversify';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
|
||||
import { DialogError, DialogMode } from '@theia/core/lib/browser/dialogs';
|
||||
import { WorkspaceInputDialog as TheiaWorkspaceInputDialog, WorkspaceInputDialogProps } from '@theia/workspace/lib/browser/workspace-input-dialog';
|
||||
|
||||
export class WorkspaceInputDialog extends TheiaWorkspaceInputDialog {
|
||||
|
||||
protected wasTouched = false;
|
||||
|
||||
constructor(
|
||||
@inject(WorkspaceInputDialogProps) protected readonly props: WorkspaceInputDialogProps,
|
||||
@inject(LabelProvider) protected readonly labelProvider: LabelProvider,
|
||||
) {
|
||||
super(props, labelProvider);
|
||||
this.appendCloseButton('Cancel');
|
||||
}
|
||||
|
||||
protected appendParentPath(): void {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
isValid(value: string, mode: DialogMode): MaybePromise<DialogError> {
|
||||
if (value !== '') {
|
||||
this.wasTouched = true;
|
||||
}
|
||||
return super.isValid(value, mode);
|
||||
}
|
||||
|
||||
protected setErrorMessage(error: DialogError): void {
|
||||
if (this.acceptButton) {
|
||||
this.acceptButton.disabled = !DialogError.getResult(error);
|
||||
}
|
||||
if (this.wasTouched) {
|
||||
this.errorMessageNode.innerText = DialogError.getMessage(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -55,3 +55,10 @@ export namespace Sketch {
|
||||
return !!arg && 'name' in arg && 'uri' in arg && typeof arg.name === 'string' && typeof arg.uri === 'string';
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Extensions {
|
||||
export const MAIN = ['.ino', '.pde'];
|
||||
export const SOURCE = ['.c', '.cpp', '.s'];
|
||||
export const ADDITIONAL = ['.h', '.c', '.hpp', '.hh', '.cpp', '.s'];
|
||||
export const ALL = Array.from(new Set([...MAIN, ...SOURCE, ...ADDITIONAL]));
|
||||
}
|
||||
|
@ -8,19 +8,13 @@ import * as fs from './fs-extra';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { FileUri, BackendApplicationContribution } from '@theia/core/lib/node';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { SketchesService, Sketch } from '../common/protocol/sketches-service';
|
||||
import { SketchesService, Sketch, Extensions } from '../common/protocol/sketches-service';
|
||||
|
||||
|
||||
// As currently implemented on Linux,
|
||||
// the maximum number of symbolic links that will be followed while resolving a pathname is 40
|
||||
const MAX_FILESYSTEM_DEPTH = 40;
|
||||
|
||||
export namespace Extensions {
|
||||
export const MAIN = ['.ino', '.pde'];
|
||||
export const SOURCE = ['.c', '.cpp', '.s'];
|
||||
export const ADDITIONAL = ['.h', '.c', '.hpp', '.hh', '.cpp', '.s'];
|
||||
}
|
||||
|
||||
// TODO: `fs`: use async API
|
||||
@injectable()
|
||||
export class SketchesServiceImpl implements SketchesService, BackendApplicationContribution {
|
||||
|
Loading…
x
Reference in New Issue
Block a user