blob: 992330b7dea93b78e3b7766c22b6a8a3c041f8c3 [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* 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
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.sdk.s2i.template
import com.intellij.codeInsight.template.impl.TemplateImpl
import org.eclipse.scout.sdk.core.s.IScoutRuntimeTypes
import org.eclipse.scout.sdk.core.util.Ensure
import org.eclipse.scout.sdk.core.util.Ensure.newFail
import org.eclipse.scout.sdk.core.util.FinalValue
import org.eclipse.scout.sdk.core.util.Strings
import org.eclipse.scout.sdk.core.util.Strings.toStringLiteral
import org.eclipse.scout.sdk.s2i.EclipseScoutBundle.Companion.message
import org.eclipse.scout.sdk.s2i.nls.NlsKeysEnumMacro
import org.eclipse.scout.sdk.s2i.template.variable.AbstractClassesEnumVariableAdapter
import org.eclipse.scout.sdk.s2i.template.variable.BoolVariableAdapter
import org.eclipse.scout.sdk.s2i.template.variable.EnumVariableAdapter
import org.eclipse.scout.sdk.s2i.template.variable.VariableDescriptor
class TemplateDescriptor(val id: String, private val resourceLoader: ClassLoader = TemplateDescriptor::class.java.classLoader) {
companion object {
const val VARIABLE_NAME = "name"
const val PREDEFINED_VARIABLE_SUPER = "super"
const val PREDEFINED_VARIABLE_MENU_TYPES = "menuTypes"
const val PREDEFINED_VARIABLE_KEYSTROKES = "keystrokes"
const val PREDEFINED_VARIABLE_COMPLETE = "complete"
const val PREDEFINED_CONSTANT_IN_EXTENSION = "inExtension"
const val PREDEFINED_CONSTANT_MENU_SUPPORTED = "menuSupported"
}
private var m_name: String? = null
private var m_description: String? = null
private var m_superClassInfo: SuperClassInfo? = null
private var m_orderDefinitionType: String? = null
private val m_source = FinalValue<String>()
private var m_innerTypeGetterInfos = LinkedHashSet<InnerTypeGetterInfo>()
private val m_variables = HashMap<String, (TemplateEngine) -> VariableDescriptor?>()
private val m_alias = HashSet<String>()
init {
// append predefined variables
withVariable(PREDEFINED_VARIABLE_MENU_TYPES, EnumVariableAdapter(PREDEFINED_VARIABLE_MENU_TYPES, PsiExpressionEnumMacro.NAME) {
it.menuTypes.map { candidate -> "${IScoutRuntimeTypes.CollectionUtility}.hashSet($candidate)" }
})
withVariable(PREDEFINED_VARIABLE_KEYSTROKES, EnumVariableAdapter(PREDEFINED_VARIABLE_KEYSTROKES, PsiExpressionEnumMacro.NAME) {
it.keyStrokes
})
withVariable(PREDEFINED_VARIABLE_SUPER, AbstractClassesEnumVariableAdapter(PREDEFINED_VARIABLE_SUPER))
withVariable(PREDEFINED_VARIABLE_COMPLETE) { VariableDescriptor(PREDEFINED_VARIABLE_COMPLETE, "complete()") }
}
constructor(original: TemplateDescriptor) : this(original.id, original.resourceLoader) {
m_name = original.m_name
m_description = original.m_description
m_superClassInfo = original.m_superClassInfo
m_orderDefinitionType = original.m_orderDefinitionType
m_innerTypeGetterInfos.addAll(original.m_innerTypeGetterInfos)
m_variables.putAll(original.m_variables)
m_alias.addAll(original.m_alias)
}
fun withName(name: String) = apply { m_name = name }
fun name() = m_name ?: ""
fun withDescription(description: String) = apply { m_description = description }
fun description() = m_description ?: message("template.desc", name())
fun withEnumVariable(name: String, values: Iterable<String>, macroName: String? = null) = withVariable(name, EnumVariableAdapter(name, macroName, values))
fun withBoolVariable(name: String, defaultValue: Boolean) = withVariable(name, BoolVariableAdapter(name, defaultValue.toString()))
fun withNlsVariable(name: String, defaultValue: String? = null) = withVariable(name) { VariableDescriptor(name, "${NlsKeysEnumMacro.NAME}()", toStringLiteral(defaultValue)?.toString()) }
fun withVariable(name: String, value: String) = withVariable(name) { VariableDescriptor(name, null, toStringLiteral(value)?.toString()) }
fun withVariable(name: String, variableAdapter: (TemplateEngine) -> VariableDescriptor?) = apply {
Ensure.isFalse(TemplateImpl.INTERNAL_VARS_SET.contains(name), "Variable name '{}' is reserved for internal use.", name)
m_variables[name] = variableAdapter
}
fun variable(name: String) = m_variables[name]
fun withAliasName(alias: String) = apply { m_alias.add(alias) }
fun withAliasNames(vararg aliases: String) = apply { aliases.filter { Strings.hasText(it) }.forEach { withAliasName(it) } }
fun aliasNames(): Set<String> = m_alias
fun withSuperClassInfo(baseFqn: String, defaultValue: String) = apply { m_superClassInfo = SuperClassInfo(baseFqn, defaultValue) }
fun superClassInfo() = m_superClassInfo
fun withOrderDefinitionType(fqn: String) = apply { m_orderDefinitionType = fqn }
fun orderDefinitionType() = m_orderDefinitionType
fun withInnerTypeGetterInfo(containerFqn: String, methodName: String, lookupType: InnerTypeGetterLookupType = InnerTypeGetterLookupType.CLOSEST) = apply { m_innerTypeGetterInfos.add(InnerTypeGetterInfo(containerFqn, methodName, lookupType)) }
fun innerTypeGetterInfos(): Set<InnerTypeGetterInfo> = m_innerTypeGetterInfos
fun source(): String = m_source.computeIfAbsentAndGet {
val templatePath = id.replace('.', '/') + ".txt"
return@computeIfAbsentAndGet resourceLoader.getResource(templatePath)?.readText() ?: throw newFail("Template source could not be found on classpath '{}' in classloader '{}'.", templatePath, resourceLoader)
}
fun copy() = TemplateDescriptor(this)
data class SuperClassInfo(val baseFqn: String, val defaultValue: String)
data class InnerTypeGetterInfo(val definitionClassFqn: String, val methodName: String, val lookupType: InnerTypeGetterLookupType = InnerTypeGetterLookupType.CLOSEST)
enum class InnerTypeGetterLookupType { CLOSEST, FARTHEST }
}