boboyr/TiecodePluginSkills

Vollständiger Leitfaden zur Entwicklung von Plugins für die Tiecode IDE (QiStudio). Abdeckung der Plugin-API (com.rapid.api.* / studio-api.jar), program.json Erweiterungspunkte, .rmx-Packaging und Implementierung verschiedener Funktionen.

Was ist TiecodePluginSkills?

Dieses Skill-Dokument ist ein umfassender Leitfaden für die Entwicklung von Plugins für die Tiecode IDE (auch bekannt als QiStudio), einer modularen, auf OSGi basierenden Entwicklungsumgebung für mobile Geräte. Es richtet sich an Entwickler, die neue Plugins (.rmx-Dateien) erstellen, bestehende modifizieren oder die Funktionsweise der Plugin-Erweiterungspunkte verstehen möchten. Die Dokumentation basiert auf der Dekompilierung der offiziellen 'studio-api-1.0-preview5.jar' und der Analyse von über einem Dutzend realer Plugins. Das Skill behandelt die Kernarchitektur der Plugins, die Struktur der program.json, wichtige Erweiterungspunkte wie 'project.manager', 'project.language' und 'application', die Implementierung von Code-Vervollständigung (TextMate, LanguageEngine, LSP), Dateibaum-Erweiterungen (PSObject/ExpansionCase), Ausführungskonfigurationen (RunConfiguration/TaskRunConfiguration), Projekttemplates (BaseTemplate), Build-Tasks (BaseTask/ToolchainService) und Toolchains. Unterstützte Plattformen sind Tiecode 4.6 und 4.7. Das Skill bietet sowohl offizielle Referenzen (Gitee-Repositories) als auch eine Community-Referenzimplementierung auf GitHub mit 8 vollständigen, kompilierbaren Plugins, darunter Go-, Scala-, Kotlin-, Linux- und AAR-Erweiterungen. Entwickler erhalten tiefgehende Einblicke in die Plugin-Entwicklung und können sofort funktionsfähige Plugins erstellen.

Funktioniert mit~Claude Code~Codex CLI✓Cursor
npx skills add boboyr/TiecodePluginSkills

Installed? Explore more Produktivität & Zusammenarbeit skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Tiecode Plugin-Entwicklung

Dokumentation zur Plugin-Entwicklung für die Tiecode IDE / QiStudio (Host-Paketname com.tiecode.develop). Der offizielle Name von Tiecode Studio ist QiStudio (die neue offene Engineering-Plattform, die als erste mobile Anwendung den OSGi-Standard implementiert und die Entwicklungsumgebung durch „Microkomponenten / Plugins“ erweitert). Quellen: Dekompilierung von studio-api-1.0-preview5.jar (com.rapid.api.*) + Code-Rekonstruktion aus über einem Dutzend echter Plugins (go, scala, kotlin, linux, aar, libgdx, installationsfreier Betrieb usw.).


Offizielle Materialien und Repositories (Wichtig)

Offizielle Gitee-Repositories

RepositoryBeschreibung
MobileIPE-Plugin-DevManualOffizielles Plugin-Entwicklungs-Tutorial (QiStudio Microkomponenten). Enthält QiStudio核心体系介绍.md, Rapid框架介绍.md, plugin/扩展点介绍.md, plugin/插件清单配置.md, plugin/注册你的微组件——插件.md
TiecodeCompiler-PublicRelease-Repository für Tiecode-Compiler (Plattformübergreifend). Enthält docs/ (Compiler-Nutzung/Syntax/Packaging/Plattform-Integrationsdokumente), headers/tiec/ (C API + C++ Wrapper-Header), prebuilt/ (CLI + android/windows/linux/ohos/wasm Dynamische Bibliotheken), stdlibs/ (Android/CXX/Web Basisbibliotheken)
QiStudio-PluginSamplesOffizielle Plugin-Beispielprojektsammlung (19+ Beispiele: Dependency Injection, Editor-Animationen/Regenbogen-Klammern, schwebendes Log-Fenster, HTML-Projektmanager, Netzwerkanfragen, Icon-Erweiterungen, Javac9-Toolchain, Syntax-Highlighting, benutzerdefinierte Themes, Application-Lifecycle, Projektkomponenten, verschiedene Menüs, Werkzeugseiten, Einstellungsseiten usw.)

Der offizielle API-Jar heißt qistudio-api-<version>.jar (das in diesem Skill dekompilierte studio-api-1.0-preview5.jar ist das SDK auf der Host-Seite). QQ-Gruppe: 1016399857.

Community-Referenzimplementierung (GitHub)

Sammlung echter Plugin-Quellcodes zu diesem Skill (Ein Repository, mehrere Verzeichnisse, 8 vollständig kompilierbare Plugins):

https://github.com/boboyr/tiecode-plugin

VerzeichnisPluginDemonstrierte Fähigkeiten
go语言工程插件/Go-Sprachprojekt (Konsole+SDL3)Doppelvorlage + LSP (gopls) Vervollständigung + TextMate Highlighting + Toolchain + Ausführungskonfiguration + Virtueller Dateibaum-Knoten
结绳安卓工程aar构建插件/AAR/JAR BuildWiederverwendung der Host-Toolchain + NameGenerator chinesische Ausgabe
结绳免安装运行插件/Installationsfreier RunnerWiederverwendung von Host-Tasks + Plugin-gestütztes Laden nicht installierter APKs
libgdx游戏编辑器插件/libgdx Visueller EditorDesigner + Editor-Codebereichsmenü + Neue Szenenklasse
scala安卓工程插件/Scala Android-ProjektVollständige sbt-Build-Kette + „Tiecode-Plugin-Projekt“-Vorlage + Build/Debug-Plugin
结绳Linux工程插件/Tiecode Linux-SDL3GCC-Toolchain + SDL3 + Task-Kette
外部kotlin文件注解插件/Externe Kotlin-Datei-AnnotationTiecode-Compiler-API: CompilerPlugin + AnnotationProcessor + Kotlin-Vervollständigung
BasicLanguages-lang参考/Offizielle BasissprachenCSML/JSON/Markdown/XML/Properties Syntax-Highlighting-Referenz

0. Kernkonzepte und Gesamtarchitektur

Tiecode ist ein modularer IDE-Host, Plugins werden als .rmx-Dateien verteilt. Eine .rmx-Datei ist im Wesentlichen ein APK: AndroidManifest.xml + classes.dex + META-INF/program.json. Der Host entdeckt die Plugin-Fähigkeiten über die Erweiterungspunkte (extension points) in der program.json, nicht über <application> oder die vier Komponenten des Manifests.

0.1 Drei wichtige Pakete

PaketZweck
com.rapid.api.*Plugin SDK (Hauptbestandteil dieses Dokuments). Projekt, Sprache, Aufgabe, Struktur, Seite, UI, Netzwerk usw.
com.rapid.framework.*Framework-Schicht: VFS (Virtuelles Dateisystem), Service/Data/Event Keys, program/plugin Container
com.tiecode.compiler.*Tiecode-Compiler (Syntaxbaum / Symboltabelle / Toolchain completer/processor) – Host-seitig, Plugins verwenden normalerweise nur das Toolchain-Unterpaket

0.2 Erweiterungspunkte (extension-Array in program.json)

Vollständige Struktur der META-INF/program.json:

{
  "id": "com.goproject.plugin",
  "name": "go语言工程插件",
  "engine": "plugin",
  "description": "...",
  "versionCode": 4,
  "versionName": "1.3",
  "minSupport": 1,
  "vendor": { "name": "boboyr", "email": "", "url": "#" },
  "extension": [
    { "point": "application", "class": "com.goproject.plugin.MyApplication" },
    { "point": "project.manager", "class": "com.goproject.plugin.project.GoProjectManager" },
    { "point": "project.language", "class": "com.goproject.plugin.lang.GoLanguageFactory",
      "scope": { "unit": "project", "identifiers": "sample.go" } },
    { "point": "domain.menu", "class": "com.goproject.plugin.Gomodmenu" }
  ]
}

Erläuterung des minSupport-Feldes (Minimale unterstützte Host-Version)

minSupport ist eine ganze Zahl, die die minimale Tiecode-Version des Hosts angibt, die das Plugin erfordert. Unterschiedliche Versionen haben unterschiedliche Werte:

Tiecode-VersionminSupportErläuterung
Tiecode 4.61Plugin für 4.6 schreibt "minSupport": 1
Tiecode 4.72Plugin für 4.7 schreibt "minSupport": 2

D.h.: Bei der Entwicklung für 4.6 wird minSupport auf 1 gesetzt; bei einem Upgrade auf 4.7 (oder für ein Plugin, das auf 4.7 abzielt) auf 2. Die genaue Bindung an die Host-Versionsnummer richtet sich nach den offiziellen Angaben; beim Entwickeln einfach entsprechend der Ziel-Hostversion ausfüllen.

Vollständige Liste der bestätigten Erweiterungspunkte (point-Feld):

ErweiterungspunktKlasse implementieren/erweiternZweckQuell-Plugin
applicationAndroidPluginPlugin-Einstiegspunkt, onInit/activate/onUninstallgo/scala/aar/installationsfrei
project.managerProjectManager (üblich CodeProjectManager)Registrierung eines Projekttypsgo/scala/linux
project.languageLanguageFactoryRegistrierung einer Sprache (Highlighting + zugehörige Dateierweiterungen), kann scope enthaltengo/scala
project.language.engineLanguageEngineRegistrierung einer Sprach-Engine (Container für Vervollständigungs-/Diagnose-Provider usw.)Tiecode-Konsolen-Plugin
project.toolchainTool-Unterklasse (z. B. SunJdk8Compiler)Registrierung einer Build-ToolchainJavaCompiler8
project.componentComponentIntegrator/ComponentFactoryHängen von Komponenten beim Öffnen eines Projekts (Ausführungskonfiguration/erstes Popup/Hook)linux/kotlin/aar/installationsfrei
project.file.creationOptionPSObjectCreationOptionMenüpunkt „Neue Datei“ im Dateibaumkotlin/libgdx
project.file.openWithEditorPSObjectOpeningOptionDatei „Öffnen mit“kotlin
project.event.fileUiProjectFileUiEventDateibaum-UI-Ereignisse (Symbole binden usw.)kotlin
domain.menuBaseDomainMenuAction/MenüaktionMenüeinträge der obersten Ebenego
domain.menu.editor.codeMenü im Editor-Codebereichlibgdx
platform.settingsBuilderSettingsBuilderNeue Unterseite in den Einstellungen hinzufügenscala android
project.file.creationOption———

Hinweis: scope.identifiers wird verwendet, um eine Sprache/Komponente auf einen bestimmten Projekt-typeId (z. B. sample.go) zu beschränken. Bei einigen Erweiterungspunkten kann die Klasse None sein (Platzhalter).


1. Plugin-Einstiegspunkt: application Erweiterungspunkt

import com.rapid.framework.program.android.app.AndroidPlugin;
import com.rapid.framework.program.android.DvmPluginDescriptor;
import com.rapid.api.Platform;
import com.rapid.api.framework.project.toolchain.ToolchainService;
import com.rapid.api.framework.project.ProjectServiceKeys;

public class MyApplication extends AndroidPlugin {
    @Override
    public void onInit(DvmPluginDescriptor descriptor) {
        // Registrierung einer benutzerdefinierten Build-Toolchain (Beispiel: Go-Compiler)
        ToolchainService service = Platform.getService(ProjectServiceKeys.TOOLCHAIN);
        service.setTool(GoCompileApiKeys.Gocompile, new BaseGoCompiler());
    }
    @Override
    public void activate() {
        // Wird einmal ausgeführt, wenn das Plugin aktiviert wird (oft für Hooks, Listener, Zusammenbau von Compiler-Plugins)
    }
    @Override
    public void onUninstall() {
        // Bereinigung beim Deinstallieren: Beenden der selbst gestarteten Unterprozesse (z. B. gopls), Trennen der LSP-Verbindung
    }
}

Wichtige API (com.rapid.api.Platform) :

  • Platform.getService(Key<T>) – Host-Dienst abrufen (z. B. ProjectServiceKeys.TOOLCHAIN)
  • Platform.getProject() – Das aktuell geöffnete Projektobjekt
  • Platform.getApplicationContext() – Host Context

2. Projekttyp: project.manager Erweiterungspunkt

Ein Plugin registriert über ProjectManager einen „Projekttyp“ (z. B. go语言工程, 结绳安卓工程).

2.1 Manager-Grundgerüst

public class GoProjectManager extends CodeProjectManager<GoProject> {
    public final static String TYPE = "go语言工程";       // Anzeigename
    public final static String IDENTIFIER = "sample.go"; // typeId, wird in project.json gespeichert

    public GoProjectManager() {
        super();
        this.fileManager = new GoFileManager();   // Optional: Benutzerdefinierter Dateimanager (Symbole binden usw.)

        // ① Datei-Öffnungsmethode (nach Erweiterung)
        fileManager.addPSObjectOpeningOption(DefaultOpeningOption.INSTANCE, ".go", ".mod");
        // ② Dateibaum-Knoten-Expansionsmethode (virtueller „Externe Bibliotheken“-Knoten)
        fileManager.addPSObjectExpansionCase(new ExternalLibrariesExpansionCase(), MARKER);
        // ③ Menüpunkt „Neue Datei“
        fileManager.addPSObjectCreationOption(new GoFileCreationOption());
        // ④ Sprach-Engine und Sprach-Factory
        languageManager.registerEngine("go", GoLanguageEngine.getInstance());
        languageManager.registerLanguageFactory(new GoLanguageFactory());
        languageManager.registerOperatorProvider(GoLanguage.ID, new GoOperatorProvider());
        // ⑤ Projekterstellungsvorlagen
        addTemplate(new GoConsoleTemplate());
        addTemplate(new GoSdl3Template());
    }

    @Override public String getIdentifier() { return IDENTIFIER; }

    @Override public TypeDescription getTypeDescription() {
        Drawable d = ContextUtils.getDrawable(AndroidPlugins.getContext(this), R.drawable.golang);
        return new TypeDescription(TYPE, TypeDescription.APPLICATION, d);
    }

    @Override public GoProject newProject() { return new GoProject(); }

    @Override public boolean isProjectDir(File file) { return false; }
}

ProjectManager-Schnittstellenmethoden (aus javap):

String getIdentifier();
TypeDescription getTypeDescription();      // Name + Typ + Symbol
List<Template<T>> getTemplates();
void addTemplate(Template<T>);
ProjectFileManager<T> getFileManager();
T newProject();
void load(T, LoadingPresentation);
boolean isProjectDir(File);                // Prüft, ob ein Verzeichnis ein Projekt dieses Typs ist
String backup(T); void delete(T);

Typkonstanten von TypeDescription: APPLICATION / CONSOLE / LIBRARY.


3. Projektobjekt und Pipeline-Assemblierung: CodeProject.prepare()

Jeder Projekttyp hat eine entsprechende Project-Unterklasse. prepare() wird vom Host beim Öffnen des Projekts aufgerufen. Zu diesem Zeitpunkt wurden die Vorlagendateien bereits geschrieben, und die Aufgabenkette, Ausführungskonfiguration und Komponenten können basierend auf dem Verzeichnisinhalt zusammengebaut werden.

public class GoProject extends CodeProject {
    @Override
    public void prepare() {
        if (GoProjectKind.isSdl3(getProjectDir())) {
            Task buildLibmain = new BuildLibmainTask();
            Task publishLib = new PublishLibTask();
            addTask(buildLibmain);
            addTask(publishLib);
            publishLib.dependsOn(buildLibmain);      // Aufgabenabhängigkeit
            addRunConfiguration(new GoSdl3RunConfiguration());
        } else {
            addTask(new CompilerGoTask());
            addTask(new RunGoTask());
            addRunConfiguration(new GoStartRunConfig());
            addRunConfiguration(new ElfRunConfig());
        }
    }
    @Override public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
}

Wichtige Methoden von CodeProject (extends BaseProject):

void prepare();
TaskContainer getTasks();  TaskExecutor getTaskExecutor();
void addTask(Task);  void setTasks(Iterable<Task>);
void addRunConfiguration(RunConfiguration);   // Nur in CodeProject
ProjectVariant getVariant();  void setVariant(ProjectVariant);
Logger getLogger();  void setLogger(Logger);
String getName();
File getProjectDir();  File getChildFile(String);   // Relativen Pfad im Projekt in File auflösen
void recycle();

ProjectVariant-Werte: DEBUG / RELEASE / UNDEFINED.

Tipp (aus dem Go-Plugin): In prepare() können dem Projekt einmalig Markierungsdateien (z. B. External Libraries) hinzugefügt werden, um bestehenden alten Projekten auf einen Schlag neue Fähigkeiten zu geben, ohne das Projekt neu erstellen zu müssen.


4. Projektvorlage: BaseTemplate

Die Vorlage bestimmt, welche Optionen im Dialog „Neues Projekt“ angezeigt werden und welche Dateien beim Erstellen geschrieben werden.

public class GoConsoleTemplate extends BaseTemplate<GoProject> {
    @Override public String getName() { return "控制台工程"; }
    @Override public Drawable getPicture() { return null; }        // Vorlagenvorschau, kann null sein
    @Override public String getDefaultProjectName() { return "我的go控制台工程"; }
    @Override public Form getForm() { return new Form(); }         // Kann Eingabefelder hinzufügen

    @Override public void create(GoProject project, Form form,
                                 Project.OnProjectCreateListener listener) {
        try {
            File file = project.getChildFile("src/main.go");
            String html = AssetUtils.readAsset(AndroidPlugins.getContext(this), "sample/main.go");
            html = html.replace("${project_name}", project.getName());
            FileUtils.writeFile(html, file);                        // In das Projektverzeichnis schreiben
            FileUtils.writeFile("module main\ngo 1.26.0", project.getChildFile("src/go.mod"));
            listener.onSuccess();                                    // Erfolgs-Callback
        } catch (IOException e) {
            listener.onFail("写出默认文件失败");                      // Fehler-Callback
        }
    }
}

Schnittstellenmethoden von Template<T>:

String getName();
Drawable getPicture();
String getDefaultProjectName();
Form getForm();          // com.rapid.framework.data.form.Form, kann addInput(new FormInput(...)) sein
void create(T, Form, OnProjectCreateListener);   // OnProjectCreateListener.onSuccess()/onFail(msg)

Ressourcen in Vorlagen: Vorlagendateien in app/src/main/assets/<name> packen, mit AssetUtils.readAsset / AssetUtils.unZipAssetsFolder(context, zipName, destDir) lesen und entpacken. (Die SDL3-Projektvorlage verwendet z. B. gosdl3_template.zip in den assets und entpackt das gesamte Archiv in das Projektverzeichnis.)


5. Build-Tasks und Toolchains: BaseTask + ToolchainService

5.1 Task BaseTask

public class CompilerGoTask extends BaseTask {
    @Override public void execute() throws TaskInterruptError {
        File output = new File(Platform.getProject().getProjectDir() + "/output");
        if (!output.exists()) output.mkdirs();
        GoCompile a = Platform.getService(ProjectServiceKeys.TOOLCHAIN)
                             .getTool(GoCompileApiKeys.Gocompile);
        if (!a.isInstalled(ctx)) { logger.info("安装工具链..."); a.install(ctx); }
        GoCompileParams p = new GoCompileParams();
        p.inputFiles = FileUtils.getGofile(srcDir);
        p.outputPath = output.getPath();
        p.options = new String[]{"build", "-o"};
        a.compile(p, new CompileOnExecutionCallback());
    }

    // Muss überschrieben werden: Standardmäßig wirft BaseTask.prepare UnsupportedOperationException;
    // und die Felder logger/variant müssen hier zugewiesen werden, sonst führt logger.info in execute() zu NPE.
    @Override public void prepare(Project project, ProjectVariant variant, Logger logger) {
        this.logger = logger;
        this.variant = variant;
        Os.setenv("GOROOT", goRoot, false);   // Umgebungsvariable setzen (android.system.Os)
    }

    @Override public String getId() { return "compileWithGo"; }   // Wird von getTaskId() in der Ausführungskonfiguration referenziert
    @Override public String getName() { return "编译到目标平台"; }
}

Task-Schnittstelle (aus javap):

String getId();  String getName();
void prepare(Project, ProjectVariant, Logger);      // Standardmäßig wird eine Ausnahme geworfen, bitte unbedingt überschreiben
void execute() throws TaskInterruptError;
TaskState getState();
void interrupt();
void dependsOn(Task...);  void dependsOn(List<Task>);
Task getDependencyTask(String);  Task getDependencyTaskByName(String);
String getIntermediatePath();  String getIntermediatePath(String);
String getOutputPath();  String getOutputPath(String);
File getGeneratedDir();

Stolperfalle (Originalkommentar aus dem Go-Plugin): Wenn logger im Task nicht zugewiesen wird, führt die Verwendung von logger.info in execute() sofort zu einem NPE, und die Toolchain-Installation wird nie ausgeführt.

5.2 Toolchain Tool + Installable

public interface Tool { /* Integrierte Keys: ANDROID_SDK/AAPT/AAPT2/D8/R8/DX/PROGUARD/
                         MANIFEST_MERGER/APK_SIGNER/JAVA_SDK/JAVA_COMPILER usw. */ }
public interface Installable {
    boolean isInstalled(Context);
    void install(Context) throws IOException;
}
  • Benutzerdefinierte Toolchains werden in application.onInit() mit ToolchainService.setTool(customKey, impl) registriert.
  • Die integrierten Android-Toolchain-Keys befinden sich alle im Tool-Interface (direkt über Platform.getService(TOOLCHAIN).getTool(Tool.AAPT2) zugänglich).
  • Wiederverwendung der Host-Toolchain (Vorgehen im AAR-Plugin / Installationsfreien Plugin): Nicht den eigenen Compiler mitliefern, sondern über getDependencyTaskByName("compileWithTiecodec") o.ä. den Host-Task als Abhängigkeit einhängen oder direkt getTaskId() wiederverwenden.

6. Ausführungskonfiguration: RunConfiguration / TaskRunConfiguration

Fügt dem Menü „Ausführen“ eines Projekts ausführbare Elemente hinzu. Am häufigsten wird TaskRunConfiguration verwendet: Sie gibt eine Aufgaben-ID an, und nach erfolgreicher Ausführung der Aufgabe wird der onResult-Callback aufgerufen.

public class GoStartRunConfig extends TaskRunConfiguration {
    public Project getProject() { return Platform.getProject(); }
    public String getTaskId() { return "RunWithGo"; }          // Zugehörige Aufgaben-ID
    public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }

    @Override
    public void onResult(boolean success, String message, File outputFile) {
        // Nach erfolgreicher Ausführung: Ergebnisse anzeigen oder nächsten Schritt ausführen
        if (success) {
            Logger logger = Platform.getProject().getLogger();
            logger.info("运行完成: " + outputFile.getPath());
        }
    }

    @Override public String getName() { return "Go 程序运行"; }
    @Override public Drawable getIcon() { return null; }
}

TaskRunConfiguration bietet auch folgende Methoden:

void setRunBeforeTaskId(String id);  // Aufgabe vor der Ausführung
void setRunAfterTaskId(String id);   // Aufgabe nach der Ausführung

RunConfiguration-Schnittstelle:

String getName();  Drawable getIcon();
String getTaskId();
ProjectVariant getVariant();
Project getProject();
void onResult(boolean, String, File);
boolean isEnabled();  void setEnabled(boolean);

7. Spracherweiterung: project.language und project.language.engine

7.1 LanguageFactory registrieren

public class GoLanguageFactory implements LanguageFactory {
    public Language createLanguage() { return new GoLanguage(); }
}

public class GoLanguage extends BaseLanguage {
    public GoLanguage() {
        super("go", "go", "Go 语言");  // ID, Erweiterung, Anzeigename
    }

    public static final Language ID = new GoLanguage();
}

7.2 LanguageEngine registrieren (Code-Vervollständigung, Diagnose)

LanguageEngine ist der Container, der verschiedene Providers verwaltet:

public class GoLanguageEngine implements LanguageEngine {
    private final GoCompletionProvider completionProvider = new GoCompletionProvider();
    private final GoDiagnosisProvider diagnosisProvider = new GoDiagnosisProvider();

    @Override public CompletionProvider getCompletionProvider() { return completionProvider; }
    @Override public DiagnosisProvider getDiagnosisProvider() { return diagnosisProvider; }
    @Override public GoToDefinitionProvider getGoToDefinitionProvider() { return null; }
    @Override public ReferenceProvider getReferenceProvider() { return null; }
    @Override public HoverProvider getHoverProvider() { return null; }
    @Override public SignatureHelpProvider getSignatureHelpProvider() { return null; }
    @Override public CodeActionsProvider getCodeActionsProvider() { return null; }
    @Override public DocumentFormattingProvider getDocumentFormattingProvider() { return null; }
}

Hinweis: LanguageEngine ist nur verfügbar, wenn das Plugin in der program.json "engine": "plugin" angibt. Der offizielle Name ist LanguageEngine; wenn der Erweiterungspunkt project.language.engine zusammen mit project.language verwendet wird, kann die IDE Standard-Highlighting + das vom Plugin bereitgestellte Engine-basierte Highlighting verwenden.

7.3 Code-Vervollständigung: CompletionProvider

public class GoCompletionProvider implements CompletionProvider {
    @Override public List<CompletionItem> getCompletionItems(CompletionContext context) {
        // context.getPosition() / getFileName() / getText()
        // Rückgabe einer Liste von Vervollständigungsvorschlägen
        return Collections.singletonList(
            new CompletionItem("fmt.Println", CompletionItemKind.FUNCTION)
        );
    }
}

8. Syntax-Highlighting (TextMate + Farbschema)

Tiecode verwendet TextMate-Grammatiken (.tmLanguage / .plist) oder .sublime-syntax für das Syntax-Highlighting. Der offizielle Weg:

  1. TextMate-Datei im Plugin bereitstellen: Die .tmLanguage-Datei in app/src/main/assets/ ablegen.
  2. Registrierung der TextMate-Grammatik im LanguageFactory/LanguageEngine (in den Beispielen nicht explizit gezeigt, von der Standardimplementierung geerbt):
public class GoLanguageFactory implements LanguageFactory {
    public Language createLanguage() {
        GoLanguage lang = new GoLanguage();
        lang.setTextMateGrammar("source.go");  // scopeName in der TextMate-Grammatik
        return lang;
    }
}

Alternative: Das Plugin kann auch direkt ein HighlightingProvider implementieren, um alle Highlighting-Logik zu steuern.


9. Dateibaum-Erweiterungen

9.1 PSObjectExpansionCase (Virtuelle Knoten)

public class ExternalLibrariesExpansionCase implements PSObjectExpansionCase {
    @Override public List<PSObject> getChildren(PSObject parent) {
        // „Externe Bibliotheken“-Knoten erweitern und Dateien/Verzeichnisse aus GoRoot anzeigen
        List<PSObject> children = new ArrayList<>();
        children.add(new PSFile("fmt", "/usr/local/go/src/fmt"));
        children.add(new PSFile("os", "/usr/local/go/src/os"));
        return children;
    }
}

9.2 PSObjectCreationOption (Menü „Neue Datei“)

public class GoFileCreationOption implements PSObjectCreationOption {
    @Override public String getName() { return "Go 文件"; }
    @Override public Drawable getIcon() { return null; }
    @Override public boolean isAvailable(PSObject parent) { return true; }

    @Override public void onCreate(PSObject parent, File targetDir) {
        // Dialog zum Erstellen einer neuen .go-Datei öffnen
        // ...
    }
}

9.3 PSObjectOpeningOption (Datei „Öffnen mit“)

public class GoModOpeningOption implements PSObjectOpeningOption {
    @Override public String getName() { return "go.mod 编辑器"; }
    @Override public boolean isAvailable(PSObject obj) {
        return obj.getName().endsWith(".mod");
    }
    @Override public void open(PSObject obj) {
        // Benutzerdefinierten Editor öffnen
    }
}

10. Menüs: domain.menu und domain.menu.editor.code

10.1 Menüeinträge der obersten Ebene (domain.menu)

public class Gomodmenu extends BaseDomainMenuAction {
    @Override public String getText() { return "Go 模块"; }
    @Override public Drawable getIcon() { return null; }
    @Override public boolean isEnabled() { return true; }

    @Override
    public void actionPerformed(AnActionEvent e) {
        // Benutzerdefinierte Aktion ausführen
        Platform.getProject().getLogger().info("Go 模块菜单被点击");
    }
}

10.2 Editor-Codebereichsmenü (domain.menu.editor.code)

public class LibgdxEditorMenu implements AnAction {
    @Override public void actionPerformed(AnActionEvent e) {
        // Aktion im Editor-Codebereich (z. B. „Szenenklasse generieren“)
    }
}

Registrierung in program.json: { "point": "domain.menu.editor.code", "class": "com.libgdx.plugin.LibgdxEditorMenu" }


11. Plattform-Erweiterungen: Einstellungen, Werkzeugseiten, Lifecycle

11.1 Einstellungsseite (platform.settingsBuilder)

public class ScalaSettingsBuilder implements SettingsBuilder {
    @Override public List<SettingPage> build() {
        return Collections.singletonList(new ScalaSettingPage("Scala 设置", new ScalaSettingsFragment()));
    }
}

11.2 Application-Lifecycle (application)

Neben onInit/activate/onUninstall kann AndroidPlugin auch folgende überschreiben:

  • onStart() / onStop() – Beim Start/Stopp der Anwendung
  • onConfigurationChanged() – Bei Konfigurationsänderungen
  • onLowMemory() – Bei Speicherknappheit

11.3 Werkzeugseite (project.component + ComponentIntegrator)

public class MyToolPageComponent implements ComponentIntegrator {
    @Override public void integrate(Project project) {
        // Dem Projekt eine Werkzeugseite hinzufügen
    }
}

Der Erweiterungspunkt project.component erlaubt es, bei Projektöffnung beliebige Komponenten einzuhängen.


12. Projektabhängigkeiten: Wiederholen der wichtigsten Erweiterungspunkte

ErweiterungspunktMuss registriert werdenOptionalHinweise
application✅Plugin-Einstiegspunkt, muss registriert werden
project.manager✅Projekttyp registrieren
project.language✅Wenn das Plugin Dateien mit Syntax-Highlighting unterstützen soll
project.language.engine✅Code-Vervollständigung/Diagnose, erfordert engine:plugin
project.toolchain✅Benutzerdefinierte Toolchain (wie Go-Compiler)
project.component✅Komponenten bei Projektöffnung einhängen (häufig verwendet)
project.file.creationOption✅Menü „Neue Datei“
domain.menu✅Menüeinträge der obersten Ebene
platform.settingsBuilder✅Einstellungsseite

Anhang A: Häufige Fallstricke und Tipps

  1. minSupport korrekt einstellen: Bei der Entwicklung für Tiecode 4.6 auf 1 setzen, für 4.7 auf 2. Falsche Einstellung kann dazu führen, dass das Plugin nicht geladen wird.
  2. Toolchain-Installation: Wenn die Toolchain nicht auf dem Gerät installiert ist, muss das Plugin diese selbst herunterladen und installieren (über Installable). Die Logger-Ausgabe muss korrekt initialisiert sein, sonst wird die Installation nicht durchgeführt.
  3. LSP-Verbindung: Bei Verwendung von LSP (wie gopls) muss in onUninstall() der Unterprozess beendet werden, sonst bleibt der LSP-Prozess auch nach der Deinstallation des Plugins bestehen.
  4. AAR-Plugin Bauen: Das AAR-Build-Plugin muss nicht seinen eigenen Compiler mitbringen, es kann den Host-Compiler über ToolchainService.getTool(Tool.ANDROID_SDK) abrufen.
  5. TextMate-Highlighting: Wenn das TextMate-Highlighting nicht angezeigt wird, überprüfen Sie, ob der scopeName der .tmLanguage-Datei mit dem im Code registrierten übereinstimmt.

Anhang B: Offizielle Plugin-Beispiele – Kurzübersicht

Plugin-TypWichtige DateienWichtigste Erweiterungspunkte
Go ProjektGoProjectManager.java, GoLanguage.java, CompilerGoTask.javaproject.manager, project.language, project.language.engine, domain.menu
AAR BuildApplication.java, AarBuildTask.javaapplication, project.component, project.manager (Typ nicht erforderlich)
InstallationsfreiMainActivity.java, RunConfig.javaapplication, project.component
Libgdx EditorLibgdxProjectManager.java, EditorMenu.javaproject.manager, domain.menu.editor.code
ScalaScalaProjectManager.java, SbtTask.javaproject.manager, project.toolchain, platform.settingsBuilder
LinuxLinuxProjectManager.java, GccTask.javaproject.manager, project.toolchain
Kotlin AnnotationCompilerPluginImpl.java, AnnotationProcessorImpl.javaapplication, project.language.engine

Anhang C: Dateiverzeichnis-Struktur eines Plugins

mein-plugin/
├── app/
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/meinplugin/
│           │       ├── MyApplication.java
│           │       ├── MyProjectManager.java
│           │       ├── MyLanguage.java
│           │       └── ...
│           ├── assets/
│           │   ├── sample/
│           │   │   └── main.go           # Vorlagendatei
│           │   └── mytemplate.zip        # Komprimierte Vorlage
│           └── META-INF/
│               └── program.json           # Plugin-Manifest
├── build.gradle
└── ...

Der META-INF/-Ordner wird normalerweise in app/src/main/ abgelegt, da program.json nach dem Packen im APK-Stammverzeichnis unter META-INF/ liegen muss.

Verwandte Skills