When you activate the plug-in, the activate function is called, and the other terms are also highly semantic; just look at the fields.
{
activate: (ctx) => {},
command: chainide.registerCommand(ctx: () {}, command: () {}, callback: () {}),
activate: () => {}
config: {
pluginId: 'chainIDE-pluginId',
version: '0.0.1',
type: PluginType.view,
active: true,
description: {
title: 'chainIDE-pluginId',
icon: '#CommentSolid',
description: 'extensionDescription'
}
}
}
The basic structure of the plugin is as follows:
src
├── chainIDE.d.ts # Generic ChainIDE definition
├── components # Components that need to be rendered in the IDE body, use react
│ ├── control.less
│ └── control.tsx
├── extension.ts # Plugin declaration
└── libs
├── index.ts
├── types
│ ├── chainIdeProxyImpl.ts
│ ├── configuration.ts
│ ├── contextEffectAction.ts
│ ├── extensionComponent.ts
│ ├── extensionEffectAction.ts
│ ├── extensionsStorage.ts
│ ├── fileSystem
│ │ └── IFileSystem.ts
│ ├── index.ts
│ ├── plugin.ts
│ ├── project
│ │ └── projectPluginsManager.ts
│ └── wallet.d.ts
└── utils
├── filterPathByRegex.ts
├── index.ts
└── toUri.ts
The code in packages/chainide/src/modules/extensions/services/manager.ts
will activate the corresponding plug-in or load the internal plug-in, you can see that it is mainly through
the this._extensionEmitter.fire this pub/sub
, to update the plug-in panel, the details will not be repeated.
activate(pluginId: string) {
const plugin = this._plugins.get(pluginId);
if (plugin) {
this.setConfiguration({ ...plugin.config, active: true });
this._extensionEmitter.fire({
type: ExtensionEffectActionType.UPDATE
});
plugin.activate(plugin.context, chainIDEProxyImpl);
plugin.context.subscriptions
.sort((NItem, OItem) => OItem.priority - NItem.priority)
.map((item) => item.active());
plugin.config.active = true;
this.setPlugin(plugin);
if (!plugin.config.internalPlugin) {
updatePluginInfo(
plugin.config,
this.currentProjectPlugin?.currentProjectId
);
}
} else {
outputService.handleErrorSingle(
getLocaleMsgFromKey('PLUGIN_LOG_PLUGIN_NOT_FOUND', {
pluginId
})
);
}
}
interface IChainIdeProxyImpl {
addControl: (data: IAddControlComponent) => ExtensionProperty;
setWelcomePage: (data: ISetWelcomeComponent) => ExtensionProperty;
registerCommand: (data: Omit<ICommand, 'id'>) => ExtensionProperty;
setWalletView: (
data: ISetBottomComponent,
cb?: () => void
) => ExtensionProperty;
registerFunction: (data: IFunction, cb?: () => void) => ExtensionProperty;
getApiFunction: (name: string) => Function | undefined;
addModule: (modulename: string, state: any) => void;
fileSystemService: IFileSystemService;
currentProject: ProjectBindPluginsConfig;
}
interface IFileSystemService {
readonly onFilesystemDidChange: Event<IFilesystemChangeEffect>;
readonly onFileIndex: Event<IFilesystemIndex>;
readonly onFileContentChange: Event<IFilesystemContentChange>;
getAllPathByRegex(uri: string, regex: string): Promise<string[]>;
openSync(uri: string): void;
closeSync(uri: string): void;
stat(uri: string): Promise<IStat | null>;
mkdir(uri: string): Promise<void>;
getFilesystemIndex(uri: string): Promise<string[]>;
download(uri: string, filename: string): Promise<void>;
delete(uri: string): Promise<void>;
copy(fromUri: string, toUri: string): Promise<string>;
move(fromUri: string, toUri: string): Promise<string>;
rename(fromUri: string, name: string): Promise<string>;
readFile(uri: string): Promise<File | null>;
writeFile(uri: string, file: File): Promise<void>;
readFileString(uri: string): Promise<string | null>;
readSurfaceDirectory(uri: string): Promise<string[] | null>;
writeFileString(uri: string, content: string): Promise<void>;
// this content will be cached when create
createFileString(uri: string, content: string): Promise<void>;
}
interface ICommandService {
registerCommand(
data: Omit<ICommand, 'id'> | Array<Omit<ICommand, 'id'>>
): ICommand[];
remove(id: string): ICommand[];
getCommandsBy(key: string): ICommand[];
clear(): void;
}
Use this service to register a command, exit the command panel in the editor by pressing the shortcut key command + p, and then carry out the registered command.
Register command
chainide.registerCommand({
name: 'test-command',
callback: () => {
// function will be excuted
}
})
interface IConsoleService {
readonly onConsoleChange: Event<ConsoleAction>;
logs(): IConsole[];
addLog(type: ConsoleLevel, message: string, detail?: string): void;
clearLog(): void;
}
Use this service to inject or delete data to the console panel of the IDE:
The basic usage is as follows:
// add log
consoleServcie.addLog('INFO', message)
// monitor log changes
consoleService.onConsoleChange(() => {
// do some data manipulation
})
interface IOutputService {
getOutputRows(): IOutputLogRow[];
getTransactionHash(): string;
handleInfo(data: IOutputLogRow[]): void;
handleInfoSingle(msg: string, source?: LogSource): void;
handleWarn(data: IOutputLogRow[]): void;
handleWarnSingle(msg: string, source?: LogSource): void;
handleError(data: IOutputLogRow[]): void;
handleErrorSingle(msg: string, source?: LogSource): void;
clearOutput(source: LogSource): void;
onRowsDidChange: Event<OutputRowsChangeEvent>;
emitTransactionHash(hash: string): void;
}
This service is similar to consoleService. It outputs information in the output panel and uses onRowsDidChange to detect information changes. It is a relatively commonly used service.
Here are related operations of the editor monoca, such as editor reporting errors, adding breakpoints, etc.
interface IExplorerService {
getExpandedFolder(projectId: string): IExpandMap;
expand(projectId: string, path: string): void;
collapse(projectId: string, path: string): void;
toggleExpand(projectId: string, path: string): void;
syncExpandWithFs(projectId: string, indexes: string[]): void;
clear(projectId: string): void;
clears(projectIds: string): void;
}
This service is used to obtain information about the file area, such as obtaining expanded folders, expanding folders, and other operations.
Basic use:
explorerService.expand(projectId, path);