|
@@ -237,6 +237,10 @@ export const NewModuleHereCommand: Command = Command.toLocalizedCommand({
|
|
|
id: 'modula2.newModuleHere', label: 'New Module Here...', category: 'Modula-2',
|
|
id: 'modula2.newModuleHere', label: 'New Module Here...', category: 'Modula-2',
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+export const NewFolderHereCommand: Command = Command.toLocalizedCommand({
|
|
|
|
|
+ id: 'modula2.newFolderHere', label: 'New Folder Here...', category: 'Modula-2',
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
@injectable()
|
|
@injectable()
|
|
|
export class Modula2ExplorerCommands implements CommandContribution {
|
|
export class Modula2ExplorerCommands implements CommandContribution {
|
|
|
@inject(WidgetManager) protected readonly widgets: WidgetManager;
|
|
@inject(WidgetManager) protected readonly widgets: WidgetManager;
|
|
@@ -255,25 +259,26 @@ export class Modula2ExplorerCommands implements CommandContribution {
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
commands.registerCommand(NewModuleHereCommand, { execute: () => this.newModuleHere() });
|
|
commands.registerCommand(NewModuleHereCommand, { execute: () => this.newModuleHere() });
|
|
|
|
|
+ commands.registerCommand(NewFolderHereCommand, { execute: () => this.newFolderHere() });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** Folder of the selected explorer file, or undefined when nothing useful is selected. */
|
|
|
|
|
- protected selectedDir(): URI | undefined {
|
|
|
|
|
|
|
+ /** Folder of the selected explorer file, else the workspace root. */
|
|
|
|
|
+ protected async selectedDir(): Promise<URI | undefined> {
|
|
|
for (const widget of this.widgets.getWidgets(MODULA2_EXPLORER_ID)) {
|
|
for (const widget of this.widgets.getWidgets(MODULA2_EXPLORER_ID)) {
|
|
|
const view = widget as Modula2ExplorerWidget;
|
|
const view = widget as Modula2ExplorerWidget;
|
|
|
const node = view.model.selectedNodes[0] as Modula2TreeNode | undefined;
|
|
const node = view.model.selectedNodes[0] as Modula2TreeNode | undefined;
|
|
|
if (node?.kind === 'file' && node.uri) {
|
|
if (node?.kind === 'file' && node.uri) {
|
|
|
- const uri = new URI(node.uri);
|
|
|
|
|
- return uri.parent;
|
|
|
|
|
|
|
+ return new URI(node.uri).parent;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return undefined;
|
|
|
|
|
|
|
+ const roots = await this.workspace.roots;
|
|
|
|
|
+ return roots[0]?.resource;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected async newModuleHere(): Promise<void> {
|
|
protected async newModuleHere(): Promise<void> {
|
|
|
- const dir = this.selectedDir();
|
|
|
|
|
|
|
+ const dir = await this.selectedDir();
|
|
|
if (!dir) {
|
|
if (!dir) {
|
|
|
- this.messages.warn('Modula-2: select a file in the Modula-2 Project view first, or use Modula-2: New Module.');
|
|
|
|
|
|
|
+ this.messages.warn('Modula-2: open a folder or workspace first.');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
const raw = await this.quickInput.input({
|
|
const raw = await this.quickInput.input({
|
|
@@ -285,7 +290,8 @@ export class Modula2ExplorerCommands implements CommandContribution {
|
|
|
const name = raw.trim();
|
|
const name = raw.trim();
|
|
|
const kind = await this.quickInput.showQuickPick(
|
|
const kind = await this.quickInput.showQuickPick(
|
|
|
[{ label: 'Implementation + definition', description: 'MyModule.mod and MyModule.def', value: 'both' },
|
|
[{ label: 'Implementation + definition', description: 'MyModule.mod and MyModule.def', value: 'both' },
|
|
|
- { label: 'Implementation only', description: 'MyModule.mod', value: 'mod' }],
|
|
|
|
|
|
|
+ { label: 'Implementation only', description: 'MyModule.mod', value: 'mod' },
|
|
|
|
|
+ { label: 'Definition only', description: 'MyModule.def', value: 'def' }],
|
|
|
{ placeholder: 'What to create?' },
|
|
{ placeholder: 'What to create?' },
|
|
|
);
|
|
);
|
|
|
if (!kind) return;
|
|
if (!kind) return;
|
|
@@ -303,20 +309,53 @@ export class Modula2ExplorerCommands implements CommandContribution {
|
|
|
this.messages.error(`Modula-2: cannot write ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
this.messages.error(`Modula-2: cannot write ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
- await write(`${name}.mod`, renderImplModule(name));
|
|
|
|
|
- if (kind.value === 'both') await write(`${name}.def`, renderDefModule(name));
|
|
|
|
|
|
|
+ if (kind.value !== 'def') await write(`${name}.mod`, renderImplModule(name));
|
|
|
|
|
+ if (kind.value !== 'mod') await write(`${name}.def`, renderDefModule(name));
|
|
|
if (created.length === 0) return;
|
|
if (created.length === 0) return;
|
|
|
this.messages.info(`Modula-2: created ${created.join(', ')}.`);
|
|
this.messages.info(`Modula-2: created ${created.join(', ')}.`);
|
|
|
try {
|
|
try {
|
|
|
await this.editors.open(dir.resolve(created[0]), { mode: 'activate' });
|
|
await this.editors.open(dir.resolve(created[0]), { mode: 'activate' });
|
|
|
} catch { /* created is enough */ }
|
|
} catch { /* created is enough */ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ protected async newFolderHere(): Promise<void> {
|
|
|
|
|
+ const dir = await this.selectedDir();
|
|
|
|
|
+ if (!dir) {
|
|
|
|
|
+ this.messages.warn('Modula-2: open a folder or workspace first.');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const raw = await this.quickInput.input({
|
|
|
|
|
+ prompt: 'Folder name (e.g. sources)',
|
|
|
|
|
+ placeHolder: 'sources',
|
|
|
|
|
+ validateInput: async value => {
|
|
|
|
|
+ const name = value.trim();
|
|
|
|
|
+ if (name.length === 0) return 'Enter a folder name.';
|
|
|
|
|
+ if (name === '.' || name === '..' || name.includes('/') || name.includes('\\')) {
|
|
|
|
|
+ return 'A single folder name, without path separators.';
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ if (raw === undefined) return;
|
|
|
|
|
+ const uri = dir.resolve(raw.trim());
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (await this.files.exists(uri)) {
|
|
|
|
|
+ this.messages.warn('Modula-2: that folder already exists.');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ await this.files.createFolder(uri);
|
|
|
|
|
+ this.messages.info(`Modula-2: created folder ${raw.trim()}.`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.messages.error(`Modula-2: cannot create folder: ${error instanceof Error ? error.message : String(error)}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export class Modula2ExplorerMenus implements MenuContribution {
|
|
export class Modula2ExplorerMenus implements MenuContribution {
|
|
|
registerMenus(menus: MenuModelRegistry): void {
|
|
registerMenus(menus: MenuModelRegistry): void {
|
|
|
const path = MODULA2_EXPLORER_CONTEXT_MENU;
|
|
const path = MODULA2_EXPLORER_CONTEXT_MENU;
|
|
|
menus.registerMenuAction(path, { commandId: NewModuleHereCommand.id, order: '10' });
|
|
menus.registerMenuAction(path, { commandId: NewModuleHereCommand.id, order: '10' });
|
|
|
|
|
+ menus.registerMenuAction(path, { commandId: NewFolderHereCommand.id, order: '11' });
|
|
|
menus.registerMenuAction(path, { commandId: 'modula2.build', order: '20' });
|
|
menus.registerMenuAction(path, { commandId: 'modula2.build', order: '20' });
|
|
|
menus.registerMenuAction(path, { commandId: RefreshExplorerCommand.id, order: '30' });
|
|
menus.registerMenuAction(path, { commandId: RefreshExplorerCommand.id, order: '30' });
|
|
|
}
|
|
}
|