mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
[generator] Added formatter fragment
Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
parent
23d213330e
commit
0670196ffb
10 changed files with 217 additions and 31 deletions
|
@ -25,5 +25,8 @@ Import-Package: com.ibm.icu.text;version="4.0.0",
|
|||
org.apache.log4j;version="1.2.15"
|
||||
Export-Package: org.eclipse.xtext.xtext.generator,
|
||||
org.eclipse.xtext.xtext.generator.builder,
|
||||
org.eclipse.xtext.xtext.generator.exporting,
|
||||
org.eclipse.xtext.xtext.generator.formatting,
|
||||
org.eclipse.xtext.xtext.generator.model,
|
||||
org.eclipse.xtext.xtext.generator.util,
|
||||
org.eclipse.xtext.xtext.generator.xbase
|
||||
|
|
|
@ -77,6 +77,10 @@ class XtextGeneratorNaming {
|
|||
new TypeReference(getRuntimeBasePackage, getName(grammar) + 'StandaloneSetupGenerated')
|
||||
}
|
||||
|
||||
def getGrammarAccess() {
|
||||
new TypeReference(getRuntimeBasePackage + '.services.' + getName(grammar) + 'GrammarAccess')
|
||||
}
|
||||
|
||||
def getEclipsePluginBasePackage() {
|
||||
if (eclipsePluginBasePackage === null)
|
||||
eclipsePluginBasePackage = getNamespace(grammar) + '.ui'
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.formatting
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap
|
||||
import com.google.common.collect.Multimap
|
||||
import com.google.inject.Inject
|
||||
import java.util.Collection
|
||||
import java.util.Set
|
||||
import org.eclipse.emf.ecore.EClass
|
||||
import org.eclipse.emf.ecore.EReference
|
||||
import org.eclipse.emf.ecore.EStructuralFeature
|
||||
import org.eclipse.xtend2.lib.StringConcatenationClient
|
||||
import org.eclipse.xtext.Grammar
|
||||
import org.eclipse.xtext.GrammarUtil
|
||||
import org.eclipse.xtext.formatting2.AbstractFormatter2
|
||||
import org.eclipse.xtext.formatting2.FormatterPreferenceValuesProvider
|
||||
import org.eclipse.xtext.formatting2.FormatterPreferences
|
||||
import org.eclipse.xtext.formatting2.IFormattableDocument
|
||||
import org.eclipse.xtext.formatting2.IFormatter2
|
||||
import org.eclipse.xtext.preferences.IPreferenceValuesProvider
|
||||
import org.eclipse.xtext.xtext.generator.AbstractGeneratorFragment2
|
||||
import org.eclipse.xtext.xtext.generator.IXtextProjectConfig
|
||||
import org.eclipse.xtext.xtext.generator.LanguageConfig2
|
||||
import org.eclipse.xtext.xtext.generator.model.FileAccessFactory
|
||||
import org.eclipse.xtext.xtext.generator.model.FileSystemAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.TypeReference
|
||||
import org.eclipse.xtext.xtext.generator.util.GenModelUtil2
|
||||
|
||||
import static extension org.eclipse.xtext.GrammarUtil.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.XtextGeneratorNaming.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.util.GrammarUtil2.*
|
||||
|
||||
class Formatter2Fragment2 extends AbstractGeneratorFragment2 {
|
||||
|
||||
@Inject IXtextProjectConfig projectConfig
|
||||
|
||||
@Inject FileAccessFactory fileAccessFactory
|
||||
|
||||
@Inject extension FileSystemAccess.Extensions
|
||||
|
||||
def TypeReference getFormatter2Stub(Grammar grammar) {
|
||||
new TypeReference(grammar.naming.runtimeBasePackage + '.formatting2.' + GrammarUtil.getName(grammar) + 'Formatter')
|
||||
}
|
||||
|
||||
override generate(LanguageConfig2 language) {
|
||||
val StringConcatenationClient statement =
|
||||
'''binder.bind(«IPreferenceValuesProvider».class).annotatedWith(«FormatterPreferences».class).to(«FormatterPreferenceValuesProvider».class);'''
|
||||
new GuiceModuleAccess.BindingFactory()
|
||||
.addTypeToType(IFormatter2.typeRef, language.grammar.formatter2Stub)
|
||||
.addConfiguredBinding(FormatterPreferences.simpleName, statement)
|
||||
.contributeTo(language.runtimeGenModule)
|
||||
new GuiceModuleAccess.BindingFactory()
|
||||
.addTypeToType('org.eclipse.xtext.ui.editor.formatting.IContentFormatterFactory'.typeRef,
|
||||
'org.eclipse.xtext.ui.editor.formatting2.ContentFormatterFactory'.typeRef)
|
||||
.contributeTo(language.eclipsePluginGenModule)
|
||||
|
||||
if (!projectConfig.runtimeSrc.containsXtendFile(language.grammar.formatter2Stub))
|
||||
doGenerateStubFile(language)
|
||||
}
|
||||
|
||||
protected def doGenerateStubFile(LanguageConfig2 language) {
|
||||
val xtendFile = fileAccessFactory.with(language).createXtendFile(language.grammar.formatter2Stub)
|
||||
|
||||
val type2ref = LinkedHashMultimap.<EClass, EReference>create
|
||||
getLocallyAssignedContainmentReferences(language.grammar, type2ref)
|
||||
val inheritedTypes = LinkedHashMultimap.<EClass, EReference>create
|
||||
getInheritedContainmentReferences(language.grammar, inheritedTypes, newHashSet)
|
||||
|
||||
xtendFile.javaContent = '''
|
||||
class «language.grammar.formatter2Stub.simpleName» extends «language.stubSuperClass» {
|
||||
|
||||
@«Inject» extension «language.naming.grammarAccess»
|
||||
«FOR type : type2ref.keySet»
|
||||
|
||||
«type.generateFormatMethod(language, type2ref.get(type), inheritedTypes.containsKey(type))»
|
||||
«ENDFOR»
|
||||
}
|
||||
'''
|
||||
xtendFile.writeTo(projectConfig.runtimeSrc)
|
||||
}
|
||||
|
||||
protected def StringConcatenationClient generateFormatMethod(EClass clazz, LanguageConfig2 language,
|
||||
Collection<EReference> containmentRefs, boolean isOverriding) '''
|
||||
«IF isOverriding»override«ELSE»def«ENDIF» dispatch void format(«clazz» «clazz.toName», extension «IFormattableDocument» document) {
|
||||
// TODO: format HiddenRegions around keywords, attributes, cross references, etc.
|
||||
«FOR ref:containmentRefs»
|
||||
«IF ref.isMany»
|
||||
for («ref.EReferenceType» «ref.name» : «clazz.toName».«ref.getGetAccessor(language)»()) {
|
||||
format(«ref.name», document);
|
||||
}
|
||||
«ELSE»
|
||||
format(«clazz.toName».«ref.getGetAccessor(language)»(), document);
|
||||
«ENDIF»
|
||||
«ENDFOR»
|
||||
}
|
||||
'''
|
||||
|
||||
protected def void getLocallyAssignedContainmentReferences(Grammar grammar, Multimap<EClass, EReference> type2ref) {
|
||||
for (assignment : grammar.containedAssignments) {
|
||||
val type = assignment.findCurrentType
|
||||
if (type instanceof EClass) {
|
||||
val feature = type.getEStructuralFeature(assignment.feature)
|
||||
if (feature instanceof EReference && (feature as EReference).isContainment) {
|
||||
type2ref.put(type, feature as EReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (action : grammar.containedActions) {
|
||||
val featureName = action.feature
|
||||
if (featureName != null) {
|
||||
val type = action.type.classifier
|
||||
if (type instanceof EClass) {
|
||||
val feature = type.getEStructuralFeature(featureName)
|
||||
if (feature instanceof EReference && (feature as EReference).isContainment) {
|
||||
type2ref.put(type, feature as EReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def void getInheritedContainmentReferences(Grammar grammar, Multimap<EClass, EReference> type2ref,
|
||||
Set<Grammar> visitedGrammars) {
|
||||
visitedGrammars.add(grammar)
|
||||
for (Grammar usedGrammar : grammar.usedGrammars) {
|
||||
if (!visitedGrammars.contains(usedGrammar)) {
|
||||
getLocallyAssignedContainmentReferences(usedGrammar, type2ref)
|
||||
getInheritedContainmentReferences(usedGrammar, type2ref, visitedGrammars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def TypeReference getStubSuperClass(LanguageConfig2 language) {
|
||||
val superGrammar = language.grammar.nonTerminalsSuperGrammar
|
||||
if (superGrammar != null)
|
||||
return superGrammar.formatter2Stub
|
||||
else
|
||||
return AbstractFormatter2.typeRef
|
||||
}
|
||||
|
||||
protected def String toName(EClass clazz) {
|
||||
clazz.name.toLowerCase
|
||||
}
|
||||
|
||||
protected def String getGetAccessor(EStructuralFeature feature, LanguageConfig2 language) {
|
||||
GenModelUtil2.getGenFeature(feature, language.resourceSet).getAccessor
|
||||
}
|
||||
|
||||
}
|
|
@ -10,9 +10,9 @@ package org.eclipse.xtext.xtext.generator.model
|
|||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.parser.IEncodingProvider
|
||||
import org.eclipse.xtext.xtext.generator.CodeConfig
|
||||
import org.eclipse.xtext.xtext.generator.LanguageConfig2
|
||||
|
||||
class FileAccessFactory {
|
||||
|
||||
|
@ -22,23 +22,28 @@ class FileAccessFactory {
|
|||
|
||||
@Inject Provider<ResourceSet> resourceSetProvider
|
||||
|
||||
@Accessors(PUBLIC_SETTER)
|
||||
ResourceSet resourceSet
|
||||
|
||||
def TextFileAccess createTextFile() {
|
||||
new TextFileAccess(encodingProvider)
|
||||
}
|
||||
|
||||
def JavaFileAccess createJavaFile(TypeReference typeRef) {
|
||||
val file = new JavaFileAccess(typeRef, codeConfig, encodingProvider)
|
||||
file.resourceSet = resourceSet ?: resourceSetProvider.get
|
||||
file.resourceSet = resourceSetProvider.get
|
||||
return file
|
||||
}
|
||||
|
||||
def XtendFileAccess createXtendFile(TypeReference typeRef) {
|
||||
val file = new XtendFileAccess(typeRef, codeConfig, encodingProvider)
|
||||
file.resourceSet = resourceSet ?: resourceSetProvider.get
|
||||
file.resourceSet = resourceSetProvider.get
|
||||
return file
|
||||
}
|
||||
|
||||
def FileAccessFactory with(LanguageConfig2 language) {
|
||||
val result = new FileAccessFactory
|
||||
result.codeConfig = this.codeConfig
|
||||
result.encodingProvider = this.encodingProvider
|
||||
result.resourceSetProvider = [language.resourceSet]
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@ import org.eclipse.emf.ecore.EClass
|
|||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.EqualsHashCode
|
||||
import org.eclipse.xtext.xtext.generator.GenModelUtil
|
||||
import org.eclipse.xtext.xtext.generator.util.GenModelUtil2
|
||||
|
||||
@Accessors
|
||||
@EqualsHashCode
|
||||
|
@ -89,7 +89,7 @@ class TypeReference {
|
|||
}
|
||||
|
||||
new(EClass clazz, ResourceSet resourceSet, List<TypeReference> arguments) {
|
||||
this(GenModelUtil.getGenClass(clazz, resourceSet).qualifiedInterfaceName, arguments)
|
||||
this(GenModelUtil2.getGenClass(clazz, resourceSet).qualifiedInterfaceName, arguments)
|
||||
}
|
||||
|
||||
private static def getPackageName(String qualifiedName) {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.xtext.generator
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.util
|
||||
|
||||
import org.eclipse.emf.codegen.ecore.genmodel.GenClass
|
||||
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier
|
||||
|
@ -26,7 +26,7 @@ import org.eclipse.emf.ecore.plugin.EcorePlugin
|
|||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
|
||||
class GenModelUtil {
|
||||
class GenModelUtil2 {
|
||||
|
||||
def static GenClass getGenClass(EClass cls, ResourceSet resourceSet) {
|
||||
return getGenClassifier(cls, resourceSet) as GenClass
|
|
@ -0,0 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.util
|
||||
|
||||
import org.eclipse.xtext.Grammar
|
||||
|
||||
class GrammarUtil2 {
|
||||
|
||||
static def boolean inherits(Grammar grammar, String languageID) {
|
||||
if (grammar.name == languageID)
|
||||
return true
|
||||
for (grammar2 : grammar.usedGrammars) {
|
||||
if (grammar2.inherits(languageID)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static def Grammar getNonTerminalsSuperGrammar(Grammar grammar) {
|
||||
grammar.usedGrammars.findFirst[name != 'org.eclipse.xtext.common.Terminals']
|
||||
}
|
||||
|
||||
}
|
|
@ -30,18 +30,19 @@ import org.eclipse.xtext.xtext.generator.model.FileSystemAccess
|
|||
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.TypeReference
|
||||
|
||||
import static extension org.eclipse.xtext.xtext.generator.GenModelUtil.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.util.GenModelUtil2.*
|
||||
import static extension org.eclipse.xtext.xtext.generator.util.GrammarUtil2.*
|
||||
|
||||
@Accessors(PUBLIC_SETTER)
|
||||
class XbaseGeneratorFragment2 extends AbstractGeneratorFragment2 {
|
||||
|
||||
static def boolean inheritsXbase(Grammar grammar) {
|
||||
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.Xbase')
|
||||
grammar.inherits('org.eclipse.xtext.xbase.Xbase')
|
||||
}
|
||||
|
||||
static def boolean inheritsXbaseWithAnnotations(Grammar grammar) {
|
||||
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations')
|
||||
grammar.inherits('org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations')
|
||||
}
|
||||
|
||||
static def boolean usesXImportSection(Grammar grammar) {
|
||||
|
|
|
@ -9,15 +9,16 @@ package org.eclipse.xtext.xtext.generator.xbase
|
|||
|
||||
import com.google.inject.Inject
|
||||
import org.eclipse.xtext.Grammar
|
||||
import org.eclipse.xtext.GrammarUtil
|
||||
import org.eclipse.xtext.xtext.generator.AbstractGeneratorFragment2
|
||||
import org.eclipse.xtext.xtext.generator.IXtextProjectConfig
|
||||
import org.eclipse.xtext.xtext.generator.LanguageConfig2
|
||||
|
||||
import static extension org.eclipse.xtext.xtext.generator.util.GrammarUtil2.*
|
||||
|
||||
class XtypeGeneratorFragment2 extends AbstractGeneratorFragment2 {
|
||||
|
||||
static def boolean inheritsXtype(Grammar grammar) {
|
||||
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.Xtype')
|
||||
grammar.inherits('org.eclipse.xtext.xbase.Xtype')
|
||||
}
|
||||
|
||||
@Inject IXtextProjectConfig projectConfig
|
||||
|
|
|
@ -270,20 +270,6 @@ public class GrammarUtil {
|
|||
collectAllUsedGrammars(grammars, grammar);
|
||||
return grammars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public static boolean inherits(Grammar grammar, String languageID) {
|
||||
if (grammar.getName().equals(languageID))
|
||||
return true;
|
||||
for (Grammar grammar2 : grammar.getUsedGrammars()) {
|
||||
if (inherits(grammar2, languageID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void collectAllUsedGrammars(List<Grammar> grammars, Grammar grammar) {
|
||||
grammars.addAll(grammar.getUsedGrammars());
|
||||
|
|
Loading…
Reference in a new issue