This is mainly code that you will encounter during theia Extension development

Students without relevant experience can first understand InversifyJS, and then directly run the official development examples, familiar with the basic development

Command

Implements the CommandContribution interface, which also shows up in the Command panel if the Command is passed in with a label field

@injectable(a)export class TestCommandContribution implements CommandContribution {
    registerCommands(commands: CommandRegistry): void {
        commands.registerCommand(SayHello, {
            execute: () = > {
                 this.messageService.info('hello hello');    / / prompt dialog box}}); }}// fontend-module.ts
bind(CommandContribution).to(LdpCommandContribution).inSingletonScope();
Copy the code

Menu

To realize MenuContribution interface, clicking will execute the Command corresponding to command-id

const SayHello: Command = {
    id: 'say:hello'.// The corresponding command ID
    label: 'Say Hello'.// The text displayed on the menu
    category: 'test'   / / class
};

@injectable(a)export class TestMenuContribution implements MenuContribution {
    registerMenus(menus: MenuModelRegistry): void {
        menus.registerMenuAction(CommonMenus.FILE, {
            commandId: SayHello.id,
            label: SayHello.label, }); }}// fontend-module.ts
bind(MenuContribution).to(LdpMenuContribution).inRequestScope();
Copy the code

Custom view

  • implementationBaseWidgetReactWidgetInterface, custom view
import * as React from 'react';
import { injectable, postConstruct, inject } from 'inversify';
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';

@injectable(a)export class WidgetWidget extends ReactWidget{
    static readonly ID = 'test:widget';
    static readonly LABEL = 'Test Widget';
    static readonly TOGGLE_COMMADND_ID = 'test.widget';

    @postConstruct(a)protected async init(): Promise<void> {
        / / initialization
        this.id = WidgetWidget.ID;
        this.title.label = WidgetWidget.LABEL;
        this.title.caption = WidgetWidget.LABEL;
        this.title.closable = true;
        this.title.iconClass = 'fa fa-window-maximize'; // example widget icon.
        this.update();    // Update the view
    }

    protected render(): React.ReactNode {
        return (
            <div>Custom view</div>)}}Copy the code
  • Inheriting abstract classesAbstractViewContribution, add the view to the correspondingDOM

In addition to widget binding methods, this class also includes bindings for commands, menus, shortcut keys, and other methods

import { injectable, inject } from 'inversify';
import { Command, CommandRegistry, MenuModelRegistry, MessageService } from '@theia/core';
import { WidgetWidget } from './widget-widget';
import { AbstractViewContribution, CommonMenus } from '@theia/core/lib/browser';

const TestCommand: Command = {
    id: 'test'.label: 'test'
}

@injectable(a)export class WidgetContribution extends AbstractViewContribution<WidgetWidget> {=
    constructor() {
        super({
            widgetId: WidgetWidget.ID,
            widgetName: WidgetWidget.LABEL,
            defaultWidgetOptions: { area: 'main'},
            toggleCommandId: WidgetWidget.ID
        });
    }

    // Bind other commands by overriding the registerCommands method
    registerCommands(commands: CommandRegistry) {
        super.registerCommands(commands);

        commands.registerCommand(TestCommand, {
            execute: () = > console.log(123)})}// Bind other menu items by rewriting the registerMenus method
    registerMenus(menus: MenuModelRegistry) {
        super.registerMenus(menus);

        menus.registerMenuAction(CommonMenus.VIEW_VIEWS, {
            commandId: TestCommand.id,
            label: TestCommand.label
        })
    }
}
Copy the code
  • Bind to the container
import { ContainerModule } from 'inversify';
import { WidgetWidget } from './widget-widget';
import { WidgetContribution } from './widget-contribution';
import { bindViewContribution, FrontendApplicationContribution, WidgetFactory } from '@theia/core/lib/browser';

export default new ContainerModule(bind= > {
    bindViewContribution(bind, WidgetContribution);
    bind(FrontendApplicationContribution).toService(WidgetContribution);
    bind(WidgetWidget).toSelf();
    bind(WidgetFactory).toDynamicValue(ctx= > ({
        id: WidgetWidget.ID,
        createWidget: () = > ctx.container.get<WidgetWidget>(WidgetWidget)
    })).inSingletonScope();
});
Copy the code

Custom editor display

This is the default editor that intercepts Theia

  • implementationOpenHandlerinterface

WidgetOpenHandler implements the OpenerHandler interface. If you have other customizations, you can implement the OpenHandler interface by following WidgetOpenHandler

  • Inheriting abstract classesWidgetOpenHandler
// widget.ts
import * as React from 'react';
import { injectable, postConstruct } from 'inversify';
import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';

@injectable(a)export class CustomWidget extends ReactWidget {
    static readonly ID = 'test:widget';
    static readonly LABEL = 'Custom Editor';

    protected text: string;

    @postConstruct(a)protected async init(): Promise<void> {
        / / initialization
        this.id = WidgetWidget.ID;
        this.title.label = WidgetWidget.LABEL;
        this.title.caption = WidgetWidget.LABEL;
        this.title.closable = true;
        this.title.iconClass = 'fa fa-window-maximize'; // example widget icon.
        this.update();    // Update the view
    }

    setText(text: string) {
        this.text = text;
    }

    // Display according to the parameters received
    protected render(): React.ReactNode {
        return (
            <React.Fragment>
                <div>Custom editor</div>
                <div>{this.text}</div>
            </React.Fragment>)}}Copy the code
/ / WidgetOpenerHandler inheritance
import { injectable } from 'inversify';
import { WidgetOpenHandler, WidgetOpenerOptions } from '@theia/core/lib/browser';
import { CustomWidget } from './widget-widget';
import URI from '@theia/core/lib/common/uri';

export interface CustomWidgetOptions {
    text: string;
}

@injectable(a)export class CustomOpenHandler extends WidgetOpenHandler<CustomWidget>  {
    readonly id = CustomWidget.ID;
    
    canHandle(uri: URI): number {
        console.log(uri.path.ext);
        if(uri.path.ext === '.json') {
            return 500;
        }
        return 0;
    }

    // Here you can set the parameters to be passed to the widgetcreateWidgetOptions(uri: URI, options? : WidgetOpenerOptions): CustomWidgetOptions{return { 
            text: 'This is a JSON file'}; }}Copy the code
// fontend-module.ts
bind(OpenHandler).toService(CustomOpenHandler);
bind(CustomOpenHandler).toSelf().inSingletonScope();    
bind(CustomWidget).toSelf();
bind(WidgetFactory).toDynamicValue(ctx= > ({
    id: CustomWidget.ID,
    createWidget: (options: CustomWidgetOptions) = > {
        const widget = ctx.container.get<CustomWidget>(CustomWidget);
        console.log(options);
        widget.setText(options.text);
        return widget;
    }
})).inSingletonScope();
Copy the code

When the JSON file is opened, our custom editor is displayed

Popup window

Framework to bring

MessageService (notification prompt box in lower right corner)

@inject(MessageService)
protected messageService: MessageService;

this.messageService.info('hello hello');
Copy the code

dialog

commands.registerCommand(DialogCommand, {
    execute: async() = > {const confirmed = await new ConfirmDialog({
            title: 'This is a confirmation box.'.msg: 'Confirmed execution? '.ok: 'confirm'.cancel: 'cancel'
        }).open();

        console.log('Have you confirmed it?', confirmed); }});Copy the code

Framework provides SingleTextInputDialog other dialog box, specific to see packages/core/SRC/browser/dialogs. Ts this directory

FileDialogService (File/Directory selection box)

  • showOpenDialog: Selects a file/directory and returns the selectedURI
commands.registerCommand(FileDialog, {
    execute: async() = > {const uri = await this.fileDialogService.showOpenDialog({
           title: 'Select directory'.canSelectFiles: false.canSelectFolders: true.openLabel: 'choose'});console.log('Select path', uri); }});Copy the code

  • showSaveDialog: Save the file dialog box
commands.registerCommand(FileDialog, {
    execute: async() = > {const uri = await this.fileDialogService.showSaveDialog({
           title: 'Select save directory'.saveLabel: 'save'
       });

       console.log('Save path', uri); }});Copy the code

Custom dialog box

Implement AbstractDialog or ReactDialog interface (specific reference packages/core/SRC/browser/dialogs. Ts other Dialog implementation)

// customDialog.tsx
import * as React from 'react';
import { inject, injectable } from 'inversify';
import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog';
import { DialogProps } from '@theia/core/lib/browser/dialogs';

// Define the input parameter
@injectable(a)export class CustomDialogProps extends DialogProps {
    readonly text: string;
    readonly okValue: string;
    readonly cancelValue: string;
}

// Define return
interface CustomDialogValue {
    text: string;
}

@injectable(a)export class CustomDialog extends ReactDialog<CustomDialogValue> {
    protected readonly text: string;

    constructor(
        @inject(CustomDialogProps) protected readonly props: CustomDialogProps
    ) {
        super(props);
        const { text, okValue, cancelValue } = this.props;
        this.text = text;
        this.appendCloseButton(cancelValue);
        this.appendAcceptButton(okValue);
    }

    protected render(): React.ReactNode {
        return (
            <div>
                {this.text}
            </div>
        );
    }

    get value() :CustomDialogValue {
        return {
            text: this.text
        }
    }
}
Copy the code
// fontend-module.ts
bind(CustomDialogProps).toSelf();
bind(CustomDialog).toSelf();
Copy the code
commands.registerCommand(SayHello, {
    execute: async() = > {const text = await new CustomDialog({
           title: 'Test dialog'.text: 'test'.okValue: 'save'.cancelValue: 'cancel'
       }).open();

        console.log('Return text', text); }});Copy the code

Implementation of a custom editor

In addition to the openHandler implementation described above, we also need to implement other editor-related functions

Github.com/eclipsesour…

File handling API

  • FlieStat
  • URI

TreeWidget

Preference

Ongoing update