Skip to content

Commit

Permalink
twirl library update in play2 plugin
Browse files Browse the repository at this point in the history
Because Play2.4 is using Twirl version 1.1.1 lib to process templates
in contrary to Play2.3 which uses Twirl version 1.0.4 there is a need
to deliver Twirl functionalities as plugins to Scala IDE Play2 Plugin.
So now it is possible to choose a Play version in Play Plugin preference
page and then correct Twirl delivers appropriate implementation of
template parser and compiler.

Implementation notes:
 - there is one global setting for Play version. So if user wants to
   work on projects of more than one Play version it is recommended to
   do it in different workspaces. The bottleneck is Twirl parser to
   which is quite hard to pass the project settings (in future cosider
   thread local?)
 - every Twirl version has its counterpart template plugin. Code is
   duplicated so far and it is result of the lack of abstraction
   for Twirl's main functionalities. Maybe in future we would need
   to improve it.

Usage notes:
 - code generated by `TwirlCompiler.compileVirtual(...)` method is
   different from generated by `TwirlCompiler.compile(...)`. The
   main diff is the use of `Html` in place of `HtmlFormat.Appendable`.
  • Loading branch information
wpopielarski committed Oct 12, 2015
1 parent 7022c41 commit 3afa79b
Show file tree
Hide file tree
Showing 39 changed files with 970 additions and 224 deletions.
8 changes: 8 additions & 0 deletions org.scala-ide.play2.templates23/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" output="target/classes" path="src"/>
<classpathentry kind="lib" path="target/lib/twirl-compiler.jar"/>
<classpathentry kind="lib" path="target/lib/twirl-parser.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
29 changes: 29 additions & 0 deletions org.scala-ide.play2.templates23/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.scala-ide.play2.templates23</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.scala-ide.sdt.core.scalabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.scala-ide.sdt.core.scalanature</nature>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
25 changes: 25 additions & 0 deletions org.scala-ide.play2.templates23/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Twirl Templates for Play 2.3
Bundle-SymbolicName: org.scala-ide.play2.templates23;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: org.scalaide.play2.templates23.Activator
Require-Bundle: org.eclipse.core.runtime,
org.scala-lang.scala-library;bundle-version="[2.11,2.12)",
org.scala-lang.scala-compiler;bundle-version="[2.11,2.12)",
org.scala-lang.scala-reflect;bundle-version="[2.11,2.12)",
org.scala-lang.modules.scala-xml,
org.scala-lang.modules.scala-parser-combinators,
org.scala-ide.play2;bundle-version="0.5.0",
org.scala-lang.scala-library
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .,
target/lib/twirl-compiler.jar,
target/lib/twirl-parser.jar
Import-Package:
com.ibm.icu.text;apply-aspects:=false;org.eclipse.swt.graphics;apply-aspects:=false,
scala.tools.eclipse.contribution.weaving.jdt.ui.javaeditor.formatter;apply-aspects:=false,
scala.xml,
scala.util.parsing.input,
scala.reflect.internal.util
9 changes: 9 additions & 0 deletions org.scala-ide.play2.templates23/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
source.. = src/
output.. = target/classes
bin.includes = plugin.xml,\
META-INF/,\
.,\
*.xml,\
target/lib,\
target/lib/twirl-compiler.jar,\
target/lib/twirl-parser.jar
14 changes: 14 additions & 0 deletions org.scala-ide.play2.templates23/plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

<extension
point="org.scalaide.play2.template.processing">
<template-processor
class="org.scalaide.play2.templates23.TemplateProcessing">
<version supports="2.3"/>
<version supports="2.2"/>
</template-processor>
</extension>

</plugin>
60 changes: 60 additions & 0 deletions org.scala-ide.play2.templates23/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.scala-ide</groupId>
<artifactId>org.scala-ide.play2.build</artifactId>
<version>0.5.0-SNAPSHOT</version>
</parent>
<artifactId>org.scala-ide.play2.templates23</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<dependencies>
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>${twirl-compiler.artifactId}</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>${twirl-parser.artifactId}</artifactId>
<version>1.0.4</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<!-- copy the play jars needed by the plugin -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>initialize</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.typesafe.play</groupId>
<artifactId>${twirl-compiler.artifactId}</artifactId>
<destFileName>twirl-compiler.jar</destFileName>
</artifactItem>
<artifactItem>
<groupId>com.typesafe.play</groupId>
<artifactId>${twirl-parser.artifactId}</artifactId>
<destFileName>twirl-parser.jar</destFileName>
</artifactItem>
</artifactItems>
<stripVersion>true</stripVersion>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.scalaide.play2.templates23

import org.osgi.framework.BundleActivator
import org.osgi.framework.BundleContext

object Activator {
@volatile
private var context: BundleContext = _

def getContext: BundleContext = context
}

class Activator extends BundleActivator {

override def start(bundleContext: BundleContext): Unit =
Activator.context = bundleContext

override def stop(bundleContext: BundleContext): Unit =
Activator.context = null

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.scalaide.play2.templates23

import java.io.File

import scala.io.Codec
import scala.util.Failure
import scala.util.Try

import org.scalaide.play2.templateeditor.compiler.PositionHelper
import org.scalaide.play2.templateeditor.compiler.TemplateToScalaCompilationError
import org.scalaide.play2.templateeditor.processing.GeneratedSource

import play.twirl.compiler.TemplateCompilationError
import play.twirl.compiler.TwirlCompiler

object Template23Compiler {
private val templateCompiler = TwirlCompiler

def compile(content: String, source: File, sourceDirectory: File, additionalImports: String, inclusiveDot: Boolean): Try[GeneratedSource] =
Try {
templateCompiler.compileVirtual(
content,
source,
sourceDirectory,
"Html",
"HtmlFormat",
additionalImports,
Codec.default,
inclusiveDot)
} map {
Template23GeneratedSource
} recoverWith {
case TemplateCompilationError(source, message, line, column) =>
val offset = PositionHelper.convertLineColumnToOffset(content, line, column)
Failure(TemplateToScalaCompilationError(source, message, offset, line, column))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.scalaide.play2.templates23

import org.scalaide.play2.templateeditor.processing.GeneratedSource

import play.twirl.compiler.GeneratedSourceVirtual

case class Template23GeneratedSource(wrapped: GeneratedSourceVirtual) extends GeneratedSource {
override def content: String = wrapped.content
override def matrix: Seq[(Int, Int)] = wrapped.matrix
override def mapPosition(generatedPosition: Int): Int = wrapped.mapPosition(generatedPosition)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.scalaide.play2.templates23

import org.scalaide.play2.templateeditor.lexical.TemplateParsing.CommentCode
import org.scalaide.play2.templateeditor.lexical.TemplateParsing.DefaultCode
import org.scalaide.play2.templateeditor.lexical.TemplateParsing.PlayTemplate
import org.scalaide.play2.templateeditor.lexical.TemplateParsing.ScalaCode
import play.twirl.parser.TreeNodes.Block
import play.twirl.parser.TreeNodes.Comment
import play.twirl.parser.TreeNodes.Def
import play.twirl.parser.TreeNodes.Display
import play.twirl.parser.TreeNodes.Plain
import play.twirl.parser.TreeNodes.PosString
import play.twirl.parser.TreeNodes.ScalaExp
import play.twirl.parser.TreeNodes.ScalaExpPart
import play.twirl.parser.TreeNodes.Simple
import play.twirl.parser.TreeNodes.Template
import play.twirl.parser.TreeNodes.TemplateTree
import play.twirl.parser.TwirlParser
import scala.util.parsing.input.Positional
import scala.util.parsing.input.NoPosition

object Template23Parser {
private[this] val parser = new TwirlParser(true)

// removes the generated yield after for
private def fixFor(s: Simple): Simple = {
if (s.code.startsWith("for(")) {
val indexOfYield = s.code.indexOf(" yield ")
if (indexOfYield == -1) {
return s
}
val newS = Simple(s.code.substring(0, indexOfYield))
newS.pos = s.pos
return newS
}
s
}

private[this] def handleScalaExpPart(scalaExpPart: ScalaExpPart): List[PlayTemplate] = scalaExpPart match {
case s @ Simple(code: String) =>
List(ScalaCode(fixFor(s)))
case Block(whitespace, args, content) =>
args.map(ScalaCode(_)).toList ::: content.flatMap(handleTemplateTree).toList
}

private def handleDef(defn: Def): List[PlayTemplate] = defn match {
case Def(name: PosString, params: PosString, code: Simple) =>
List(ScalaCode(name), ScalaCode(params), ScalaCode(code))
}

private def handleTemplateTree(templateTree: TemplateTree): List[PlayTemplate] = templateTree match {
case p @ Plain(text: String) =>
List(DefaultCode(p))
case Display(exp: ScalaExp) =>
handleTemplateTree(exp)
case cm @ Comment(msg: String) =>
List(CommentCode(cm))
case ScalaExp(parts) =>
parts.flatMap(handleScalaExpPart).toList
}

private def handleTemplate(template: Template): List[PlayTemplate] = template match {
case Template(name, comment, params, topImports, imports, defs, sub, content) =>
val namePart = if (name != null && name.str.length != 0) List(ScalaCode(name)) else List()
val commentPart = comment.map(CommentCode(_)).toList
val paramsPart = if (params.pos != NoPosition) List(ScalaCode(params)) else List()
val importsPart = (topImports ++ imports).map(ScalaCode(_)).toList
val defsPart = defs.flatMap(handleDef).toList
val subsPart = sub.flatMap(handleTemplate).toList
val contentPart = content.flatMap(handleTemplateTree).toList
namePart ::: commentPart ::: paramsPart ::: importsPart ::: defsPart ::: subsPart ::: contentPart
}

/**
* Returns list of different types of region of the template code
*/
def parse(templateCode: String): List[PlayTemplate] = {
val result = parser.parse(templateCode) match {
case parser.Success(p, _) => handleTemplate(p)
case parser.Error(p, rest, errors) => handleTemplate(p)
}
result
}

def length(input: Positional): Int = input match {
case Simple(code) =>
code.length
case Plain(code) =>
code.length
case PosString(str) =>
str.length
case Comment(str) =>
str.length + "@**@".length
case _ =>
-1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.scalaide.play2.templates23

import java.io.File

import scala.io.Codec
import scala.util.Try
import scala.util.parsing.input.Positional

import org.scalaide.play2.templateeditor.lexical.TemplateParsing.PlayTemplate
import org.scalaide.play2.templateeditor.processing.GeneratedSource
import org.scalaide.play2.templateeditor.processing.{ TemplateProcessing => PlayProcessing }

class TemplateProcessing extends PlayProcessing {
def compile(content: String, source: File, sourceDirectory: File, additionalImports: String, codec: Codec, inclusiveDot: Boolean): Try[GeneratedSource] =
Template23Compiler.compile(content, source, sourceDirectory, additionalImports, inclusiveDot)

def parse(templateCode: String): List[PlayTemplate] = Template23Parser.parse(templateCode)

def length(input: Positional): Int = Template23Parser.length(input)
}
8 changes: 8 additions & 0 deletions org.scala-ide.play2.templates24/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" output="target/classes" path="src"/>
<classpathentry kind="lib" path="target/lib/twirl-compiler.jar"/>
<classpathentry kind="lib" path="target/lib/twirl-parser.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
29 changes: 29 additions & 0 deletions org.scala-ide.play2.templates24/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.scala-ide.play2.templates24</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.scala-ide.sdt.core.scalabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.scala-ide.sdt.core.scalanature</nature>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Loading

0 comments on commit 3afa79b

Please sign in to comment.