Xtextのジェネレーターのメモ。
|
|
“Xtextで生成されたエディター”で入力したDSLから、他のファイルを生成することが出来る。
Xtextでエディターを生成すると、IGeneratorインターフェースを実装したMyDslGeneratorといったクラスが作られる(デフォルトでは中身は空)。
DSLファイルを保存するとこのクラスが呼ばれるので、その中で独自のコンパイル(ファイル生成)を行うことが出来る。
また、Eclipseプロジェクトのクリーンを行った際にも、各ファイル毎に呼ばれる。[2014-08-02]
import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.IFileSystemAccess; import org.eclipse.xtext.generator.IGenerator;
public class BatchDslGenerator implements IGenerator { public void doGenerate(Resource resource, IFileSystemAccess fsa) { StringBuilder sb = new StringBuilder(1024); EList<EObject> list = resource.getContents(); for (EObject object : list) { 〜sbにファイルの内容を構築〜 } String fileName = "hoge/test.txt"; fsa.generateFile(fileName, sb); } }
IFileSystemAccess#generateFile()で、ファイルにテキストを保存する。
ファイルのパスは、デフォルトでは「プロジェクト/src-gen」の下になる。
これは、EclipseのPreference(設定ページ)(ツリーは「自分のDSL」→「Compiler」)で変更することが出来る。
ファイル保存時にジェネレーターを呼び出すかどうかは、設定ページやプロパティーページのCompilerページでユーザーが指定できる。[2014-08-02]
Compilerページの「General」→「Compiler is activated」メニューのチェックを外すと、ジェネレーターが呼ばれなくなる。
※Eclipseプロジェクト全体の設定である「Build Automatically(自動的にビルド)」がオフになっている場合も、ジェネレーターは呼ばれない。
→独自の設定ページ(プロパティーページ)でオン・オフを設定する方法
Xtextのジェネレーター機能を使わない場合、設定ページやプロパティーページのCompilerページは不要である。[2013-09-21]
Compilerページを消すには、plugin.xmlのジェネレーター関連部分を削除する。
<!-- <extension point="org.eclipse.xtext.builder.participant"> <participant class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.IXtextBuilderParticipant"> </participant> </extension> <extension point="org.eclipse.ui.preferencePages"> <page category="jp.hishidama.xtext.dmdl_editor.DMDL" class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage" id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.preferencePage" name="Compiler"> <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/> </page> </extension> <extension point="org.eclipse.ui.propertyPages"> <page category="jp.hishidama.xtext.dmdl_editor.DMDL" class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage" id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.propertyPage" name="Compiler"> <keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/> <enabledWhen> <adapt type="org.eclipse.core.resources.IProject"/> </enabledWhen> <filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/> </page> </extension> -->
設定ページやプロパティーページのCompilerページには、生成時のオプション(作成場所とか)を指定できるようになっている。[2014-08-02]
このうち、ジェネレーター(自動ビルド)の使用有無だけユーザーに指定させたいような場合は、Compilerページを使用しないようにし、自分独自の設定ページ(プロパティーページ)で指定できるようにすればよい。
<extension
point="org.eclipse.xtext.builder.participant">
<participant
class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.IXtextBuilderParticipant">
</participant>
</extension>
<!-- デフォルトのCompilerページを無効化する
<extension
point="org.eclipse.ui.preferencePages">
<page
category="jp.hishidama.xtext.dmdl_editor.DMDL"
class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.preferencePage"
name="Compiler">
<keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
</page>
</extension>
<extension
point="org.eclipse.ui.propertyPages">
<page
category="jp.hishidama.xtext.dmdl_editor.DMDL"
class="jp.hishidama.xtext.dmdl_editor.ui.DMDLExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
id="jp.hishidama.xtext.dmdl_editor.DMDL.compiler.propertyPage"
name="Compiler">
<keywordReference id="jp.hishidama.xtext.dmdl_editor.ui.keyword_DMDL"/>
<enabledWhen>
<adapt type="org.eclipse.core.resources.IProject"/>
</enabledWhen>
<filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/>
</page>
</extension>
-->
import org.eclipse.jface.preference.BooleanFieldEditor; import org.eclipse.swt.widgets.Composite; import org.eclipse.xtext.builder.preferences.BuilderPreferenceAccess; import org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage;
@SuppressWarnings("restriction") public class DMDLRootPreferencePage extends LanguageRootPreferencePage { public static final String FORMAT_ON_SAVE = "formatOnSave";
@Override
protected void createFieldEditors() {
Composite parent = getFieldEditorParent();
addField(new BooleanFieldEditor(FORMAT_ON_SAVE, "format dmdl source on save", parent));
addField(new BooleanFieldEditor(BuilderPreferenceAccess.PREF_AUTO_BUILDING, "auto building", parent));
}
}
ジェネレーター(自動ビルド)の使用有無の設定キー(PREF_AUTO_BUILDING)はBuilderPreferenceAccessで定義されている。
ただしこのクラスは(Eclipseプラグインのルールに従って)非公開なので、無理やり使っている。(restrictionの警告が出るので、抑止している)
ビルドが発生する(ジェネレーターが呼ばれる)のは、ファイルを保存した時やEclipseのプロジェクトのクリーンを実行した時である。[2014-08-02]
どういう理由で呼ばれたのかは、IBuildContextで保持されている。
ただし、IGeneratorには渡されないので、使いたいなら、IGeneratorを呼び出しているBuilderParticipantで何とかする必要がある。
import jp.hishidama.xtext.dmdl_editor.generator.DMDLGenerator; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.xtext.builder.BuilderParticipant; import org.eclipse.xtext.generator.IGenerator;
public class DMDLBuilderParticipant extends BuilderParticipant { @Override public void build(final IBuildContext context, IProgressMonitor monitor) throws CoreException { DMDLGenerator gen = (DMDLGenerator) getGenerator(); // Xtext2.8まで long time = (context.getBuildType() == BuildType.FULL) ? System.currentTimeMillis() : 0; gen.setFullBuildStartTime(time); super.build(context, monitor); } }
public class DMDLUiModule extends jp.hishidama.xtext.dmdl_editor.ui.AbstractDMDLUiModule { 〜
@Override public Class<? extends org.eclipse.xtext.builder.IXtextBuilderParticipant> bindIXtextBuilderParticipant() { return DMDLBuilderParticipant.class; } }
Xtext2.9で、getGenerator()メソッドが非推奨になった。[2016-02-04]
しかも返ってくるインスタンスがGeneratorDelegateになったので、今までの自分のGeneratorでは無くなった。
つまり、上記の様にキャストしていると、ClassCastExceptionが発生してしまう。
Xtext2.9では、GeneratorDelegateのgetLegacyGeneratorメソッドで従来のIGeneratorが取得できる。
import org.eclipse.xtext.generator.GeneratorDelegate;
@Override public void build(final IBuildContext context, IProgressMonitor monitor) throws CoreException { @SuppressWarnings("deprecation") GeneratorDelegate delegate = (GeneratorDelegate) getGenerator(); DMDLGenerator gen = (DMDLGenerator) delegate.getLegacyGenerator(); long time = (context.getBuildType() == BuildType.FULL) ? System.currentTimeMillis() : 0; gen.setFullBuildStartTime(time); super.build(context, monitor); }