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 vonstudio-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
| Repository | Beschreibung |
|---|---|
| MobileIPE-Plugin-DevManual | Offizielles Plugin-Entwicklungs-Tutorial (QiStudio Microkomponenten). Enthält QiStudio核心体系介绍.md, Rapid框架介绍.md, plugin/扩展点介绍.md, plugin/插件清单配置.md, plugin/注册你的微组件——插件.md |
| TiecodeCompiler-Public | Release-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-PluginSamples | Offizielle 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 dekompiliertestudio-api-1.0-preview5.jarist 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
| Verzeichnis | Plugin | Demonstrierte Fähigkeiten |
|---|---|---|
go语言工程插件/ | Go-Sprachprojekt (Konsole+SDL3) | Doppelvorlage + LSP (gopls) Vervollständigung + TextMate Highlighting + Toolchain + Ausführungskonfiguration + Virtueller Dateibaum-Knoten |
结绳安卓工程aar构建插件/ | AAR/JAR Build | Wiederverwendung der Host-Toolchain + NameGenerator chinesische Ausgabe |
结绳免安装运行插件/ | Installationsfreier Runner | Wiederverwendung von Host-Tasks + Plugin-gestütztes Laden nicht installierter APKs |
libgdx游戏编辑器插件/ | libgdx Visueller Editor | Designer + Editor-Codebereichsmenü + Neue Szenenklasse |
scala安卓工程插件/ | Scala Android-Projekt | Vollständige sbt-Build-Kette + „Tiecode-Plugin-Projekt“-Vorlage + Build/Debug-Plugin |
结绳Linux工程插件/ | Tiecode Linux-SDL3 | GCC-Toolchain + SDL3 + Task-Kette |
外部kotlin文件注解插件/ | Externe Kotlin-Datei-Annotation | Tiecode-Compiler-API: CompilerPlugin + AnnotationProcessor + Kotlin-Vervollständigung |
BasicLanguages-lang参考/ | Offizielle Basissprachen | CSML/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
| Paket | Zweck |
|---|---|
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-Version | minSupport | Erläuterung |
|---|---|---|
| Tiecode 4.6 | 1 | Plugin für 4.6 schreibt "minSupport": 1 |
| Tiecode 4.7 | 2 | Plugin für 4.7 schreibt "minSupport": 2 |
D.h.: Bei der Entwicklung für 4.6 wird
minSupportauf1gesetzt; bei einem Upgrade auf 4.7 (oder für ein Plugin, das auf 4.7 abzielt) auf2. 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):
| Erweiterungspunkt | Klasse implementieren/erweitern | Zweck | Quell-Plugin |
|---|---|---|---|
application | AndroidPlugin | Plugin-Einstiegspunkt, onInit/activate/onUninstall | go/scala/aar/installationsfrei |
project.manager | ProjectManager (üblich CodeProjectManager) | Registrierung eines Projekttyps | go/scala/linux |
project.language | LanguageFactory | Registrierung einer Sprache (Highlighting + zugehörige Dateierweiterungen), kann scope enthalten | go/scala |
project.language.engine | LanguageEngine | Registrierung einer Sprach-Engine (Container für Vervollständigungs-/Diagnose-Provider usw.) | Tiecode-Konsolen-Plugin |
project.toolchain | Tool-Unterklasse (z. B. SunJdk8Compiler) | Registrierung einer Build-Toolchain | JavaCompiler8 |
project.component | ComponentIntegrator/ComponentFactory | Hängen von Komponenten beim Öffnen eines Projekts (Ausführungskonfiguration/erstes Popup/Hook) | linux/kotlin/aar/installationsfrei |
project.file.creationOption | PSObjectCreationOption | Menüpunkt „Neue Datei“ im Dateibaum | kotlin/libgdx |
project.file.openWithEditor | PSObjectOpeningOption | Datei „Öffnen mit“ | kotlin |
project.event.fileUi | ProjectFileUiEvent | Dateibaum-UI-Ereignisse (Symbole binden usw.) | kotlin |
domain.menu | BaseDomainMenuAction/Menüaktion | Menüeinträge der obersten Ebene | go |
domain.menu.editor.code | Menü im Editor-Codebereich | libgdx | |
platform.settingsBuilder | SettingsBuilder | Neue Unterseite in den Einstellungen hinzufügen | scala android |
project.file.creationOption | — | — | — |
Hinweis:
scope.identifierswird verwendet, um eine Sprache/Komponente auf einen bestimmten Projekt-typeId (z. B.sample.go) zu beschränken. Bei einigen Erweiterungspunkten kann die KlasseNonesein (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 ProjektobjektPlatform.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
loggerim Task nicht zugewiesen wird, führt die Verwendung vonlogger.infoinexecute()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()mitToolchainService.setTool(customKey, impl)registriert. - Die integrierten Android-Toolchain-Keys befinden sich alle im
Tool-Interface (direkt überPlatform.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 direktgetTaskId()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:
LanguageEngineist nur verfügbar, wenn das Plugin in der program.json"engine": "plugin"angibt. Der offizielle Name istLanguageEngine; wenn der Erweiterungspunktproject.language.enginezusammen mitproject.languageverwendet 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:
- TextMate-Datei im Plugin bereitstellen: Die
.tmLanguage-Datei inapp/src/main/assets/ablegen. - 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
HighlightingProviderimplementieren, 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 AnwendungonConfigurationChanged()– Bei KonfigurationsänderungenonLowMemory()– 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.componenterlaubt es, bei Projektöffnung beliebige Komponenten einzuhängen.
12. Projektabhängigkeiten: Wiederholen der wichtigsten Erweiterungspunkte
| Erweiterungspunkt | Muss registriert werden | Optional | Hinweise |
|---|---|---|---|
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
minSupportkorrekt einstellen: Bei der Entwicklung für Tiecode 4.6 auf1setzen, für 4.7 auf2. Falsche Einstellung kann dazu führen, dass das Plugin nicht geladen wird.- 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. - 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. - 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. - TextMate-Highlighting: Wenn das TextMate-Highlighting nicht angezeigt wird, überprüfen Sie, ob der
scopeNameder.tmLanguage-Datei mit dem im Code registrierten übereinstimmt.
Anhang B: Offizielle Plugin-Beispiele – Kurzübersicht
| Plugin-Typ | Wichtige Dateien | Wichtigste Erweiterungspunkte |
|---|---|---|
| Go Projekt | GoProjectManager.java, GoLanguage.java, CompilerGoTask.java | project.manager, project.language, project.language.engine, domain.menu |
| AAR Build | Application.java, AarBuildTask.java | application, project.component, project.manager (Typ nicht erforderlich) |
| Installationsfrei | MainActivity.java, RunConfig.java | application, project.component |
| Libgdx Editor | LibgdxProjectManager.java, EditorMenu.java | project.manager, domain.menu.editor.code |
| Scala | ScalaProjectManager.java, SbtTask.java | project.manager, project.toolchain, platform.settingsBuilder |
| Linux | LinuxProjectManager.java, GccTask.java | project.manager, project.toolchain |
| Kotlin Annotation | CompilerPluginImpl.java, AnnotationProcessorImpl.java | application, 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 inapp/src/main/abgelegt, daprogram.jsonnach dem Packen im APK-Stammverzeichnis unterMETA-INF/liegen muss.