Giter Club home page Giter Club logo

twirl's Introduction

Twirl

Twitter Follow Discord GitHub Discussions StackOverflow YouTube Twitch Status OpenCollective

Build Status Maven Repository size Scala Steward badge Mergify Status

Twirl is the Play template engine.

Twirl is automatically available in Play projects and can also be used stand-alone without any dependency on Play.

See the Play documentation for the template engine for more information about the template syntax.

sbt-twirl

Twirl can also be used outside of Play. An sbt plugin is provided for easy integration with Scala or Java projects.

sbt-twirl requires sbt 1.3.0 or higher.

To add the sbt plugin to your project add the sbt plugin dependency in project/plugins.sbt:

// twirl 2.0 and newer:
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "LATEST_VERSION")
// twirl 1.6:
addSbtPlugin("com.typesafe.play" % "sbt-twirl" % "1.6.1")
// twirl 1.5.1 and before:
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.1")

Replacing the LATEST_VERSION with the latest version published, which should be Latest version. And enable the plugin on projects using:

someProject.enablePlugins(SbtTwirl)

If you only have a single project and are using a build.sbt file, create a root project and enable the twirl plugin like this:

lazy val root = (project in file(".")).enablePlugins(SbtTwirl)

Template files

Twirl template files are expected to be placed under src/main/twirl or src/test/twirl, similar to scala or java sources. The source locations for template files can be configured.

Template files must be named {name}.scala.{ext} where ext can be html, js, xml, or txt.

The Twirl template compiler is automatically added as a source generator for both the main/compile and test configurations. When you run compile or Test/compile the Twirl compiler will generate Scala source files from the templates and then these Scala sources will be compiled along with the rest of your project.

Additional imports

To add additional imports for the Scala code in template files, use the templateImports key. For example:

TwirlKeys.templateImports += "org.example._"

Source directories

To configure the source directories where template files will be found, use the compileTemplates / sourceDirectories key. For example, to have template sources alongside Scala or Java source files:

Compile / TwirlKeys.compileTemplates / sourceDirectories := (Compile / unmanagedSourceDirectories).value

maven-twirl

To use the Twirl plugin in your project add the Maven plugin and Twirl API as a dependency into pom.xml:

<dependencies>
    <dependency>
        <groupId>org.playframework.twirl</groupId>
        <artifactId>twirl-api_${SCALA_VERSION}</artifactId>
        <version>${TWIRL_VERSION}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.playframework.twirl</groupId>
            <artifactId>twirl-maven-plugin_${SCALA_VERSION}</artifactId>
            <version>${TWIRL_VERSION}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Replacing the TWIRL_VERSION with the latest version published, which should be Latest version.

Template files

Twirl template files are expected to be placed under src/main/twirl or src/test/twirl, similar to scala or java sources. The additional source locations for template files can be configured.

Template files must be named {name}.scala.{ext} where ext can be html, js, xml, or txt.

Additional imports

To add additional imports for the Scala code in template files, use the templateImports parameter. For example:

<plugin>
    <groupId>org.playframework.twirl</groupId>
    <artifactId>twirl-maven-plugin_${SCALA_VERSION}</artifactId>
    <version>${TWIRL_VERSION}</version>
    <configuration>
        <templateImports>
            <import>org.example._</import>
        </templateImports>
    </configuration>
</plugin>

Source directories

To configure the source directories where template files will be found, use the sourceDir parameter. For example:

<plugin>
    <groupId>org.playframework.twirl</groupId>
    <artifactId>twirl-maven-plugin_${SCALA_VERSION}</artifactId>
    <version>${TWIRL_VERSION}</version>
    <configuration>
        <sourceDir>${project.basedir}/src/main/templates</sourceDir>
    </configuration>
    <executions>
        <execution>
            <id>additional-source-directory</id>
            <goals>
                <goal>compile</goal>
            </goals>
            <configuration>
                <sourceDir>${project.basedir}/src/main/other-templates</sourceDir>
            </configuration>
        </execution>
    </executions>
</plugin>

Scala version

To configure the Scala version just use the suffix in artifactId.

Other properties

Also, you can use the next parameters:

<plugin>
    <groupId>org.playframework.twirl</groupId>
    <artifactId>twirl-maven-plugin_${SCALA_VERSION}</artifactId>
    <version>${TWIRL_VERSION}</version>
    <configuration>
        <constructorAnnotations>
            <annotation>@org.example.MyAnnotation()</annotation>
        </constructorAnnotations>
        <templateFormats>
            <csv>play.twirl.api.TxtFormat</csv>
        </templateFormats>
        <sourceEncoding>UTF-8</sourceEncoding>
    </configuration>
</plugin>

Snapshots

To use a snapshot version add the Sonatype Snapshot repository into pom.xml:

<pluginRepositories>
    <pluginRepository>
        <id>sonatype-snapshots</id>
        <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

gradle-twirl

⚠️ org.playframework.twirl plugin requires Gradle 7.1 or higher.

To use the Twirl plugin in your project add the gradle plugin and Twirl API as a dependency into build.gradle.kts:

plugins {
  ...
  id("org.playframework.twirl") version "LATEST_VERSION"
}

dependencies {
  implementation("org.playframework.twirl", "twirl-api_${scalaVersion}", "LATEST_VERSION")
}

Replacing the LATEST_VERSION with the latest version published, which should be Latest version.

Template files

Twirl template files are expected to be placed under src/main/twirl or src/test/twirl, similar to scala or java sources. The additional source locations for template files can be configured.

⚠️Please note that the output of the template compilation is Scala source code. If you use these templates in your Java source files, you must place them in a joint compilation folder (see the Gradle Scala Plugin documentation for details). The default location for this folder is src/main/scala, but it can be customized.

Template files must be named {name}.scala.{ext} where ext can be html, js, xml, or txt.

Additional imports

To add additional imports for the Scala code in template files, use the templateImports key. For example:

sourceSets {
  main {
    twirl {
      templateImports.add("org.example._")
    }
  }
}

Source directories

To configure the source directories where template files will be found, use the srcDir method for SourceDirectorySet. For example:

sourceSets {
  main {
    twirl {
      srcDir("app")
    }
  }
}

Scala version

To configure the Scala version use the scalaVersion property of TwirlExtension (2.13 by default). For example:

twirl {
  scalaVersion.set("3")
}

Other properties

Also, you can use the next properties:

sourceSets {
  main {
    twirl {
      // Annotations added to constructors in injectable templates
      constructorAnnotations.add("@org.example.MyAnnotation()")
      // Defined custom twirl template formats
      templateFormats.put("csv", "play.twirl.api.TxtFormat")
      // Source encoding for template files and generated scala files
      sourceEncoding.set("<enc>")
    }
  }
}

Snapshots

To use a snapshot version add the Sonatype Snapshot repository into settings.gradle.kts:

pluginManagement {
  repositories {
    maven {
      url = uri("https://oss.sonatype.org/content/repositories/snapshots")
    }
  }
}

Releasing a new version

See https://github.com/playframework/.github/blob/main/RELEASING.md

Credits

The name twirl was thought up by the Spray team and refers to the magic @ character in the template language, which is sometimes called "twirl".

The first stand-alone version of Twirl was created by the Spray team.

An optimized version of the Twirl parser was contributed by the Scala IDE team.

twirl's People

Contributors

ahjohannessen avatar benmccann avatar billyautrey avatar brbrown25 avatar dependabot[bot] avatar dwijnand avatar ennru avatar gkossakowski avatar gmethvin avatar ignasi35 avatar ihostage avatar jroper avatar julienrf avatar marcospereira avatar mergify[bot] avatar mkurz avatar octonato avatar pvlugter avatar raboof avatar renovate[bot] avatar richdougherty avatar scala-steward avatar schmitch avatar sethtisue avatar sullis avatar tototoshi avatar tylersouthwick avatar wsargent avatar xuwei-k avatar yousuketto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twirl's Issues

scalajs support

It will be great to be able to share some templates between backend and frontend

pluggable template post-compilation rendering (by extension) support

I'd like to see post-processing support beyond the existing format options:

Template files must be named {name}.scala.{ext} where ext can be html, js, xml, or txt.

For example, a .scala.jade file would compile from twirl into scala, then the embedded text would convert from jade into html (which I imagine would show errors in context of jade code for easier debugging) or: jade processes into html, then from there into scala (which is probably more efficient). These are my assumptions without knowing too much of twirl's underlying architecture.

Is this a feature worth pursuing?

Compile only prototype in dev mode

Hi.
Compilation time of Scala is slow, so it is for twirl.
It could be improved if in dev mode if it will be parsed/generated only function prototype(name and parameters) and imports, the body of function will be compiled only for specific page in runtime when is loaded, so it will compile only a few templates and it will be fast and in controller the call of template will be safe.
It could be added as an option.

In prod mode should be the same as it is now.

Thanks.

Template naming not consistent

I have a project with a simple template login.scala.html and it generated views.html.**login**.template.scala in an activator compilation but in pure sbt build it generated views.html.**logIn**.template.scala. Naturally, this is resulting in compilation errors and broken builds.

Is there any way to force naming style (as-is/camelCase)? Or is there any best practice to be consistent across builds?

Thanks!

Injectable templates

One problem with eliminating global state in Play is that now everything, eg CSRF, i18n, reverse routing, assets rendering etc needs to be passed into each template every time its invoked. This is manageable (though not ideal) in Scala, but for Java users it leaves a lot to be desired. One solution to this is to make templates themselves injectable. I propose the following syntax:

@*
 * Some template
 *@
@this(templateContext: Context)

@(title: String)

...

The this keyword will be for defining constructors. this is already a reserved word in Twirl by virtue of the fact that it's a Scala reserved word, and the this() syntax is somewhat consistent with Scala constructor syntax. The above template would compile (roughly) to this:

class someTemplate @Inject() (templateContext: Context) extends Template1[String] {
  def apply(title: String) = { ... }
}

while, if no @this directive is specified, it will be compiled to an object as before. Hence this should be 100% backwards compatible.

Templates could of course depend on each other, by declaring each other in their constructors, for example, the index template might depend on the main template:

main.scala.html:

@this(templateContext: Context)

@(title: String)(content: Html)

<html>
  <head><title>@title</title></head>
  <body>@content</body>
</html>

index.scala.html:

@this(templateContext: Context, main: views.html.main)

@main("Index") {
  <h1>Hello world!</h1>
}

Note that of course the Context type above is just a fictitious type that we may provide in Play as a convenience to provide web template utilities in one place, such as i18n, assets reverse routing/CDN/finger printing configuration, CSRF config, etc.

Value Raw is not a member of String error with variable named format present

Sometimes variable names lead to this misterious error

Here is example that I found on the internet http://www.ethanjoachimeldridge.info/tech-blog/value-raw-not-member-string-scala

[error] /path/app/views/common/templateNotFound.scala.xml:4: value raw is not a member of String
[error] The template or the format does exist
[error] ^
[error] one error found
error Compilation failed

View did not compile with variables @(template: String, format: String) and compiled with variable names @(badTemplate: String, badFormat: String)

I also had to rename String variable format to outputFormat to avoid this issue

HtmlFormat.escape should be defensive about nulls

If null is passed to HtmlFormat.escape, then it should probably be defensive about that and not throw an NPE.

Either that, or a check should be done earlier that ensures that null isn't passed to it.

Whatever the solution, I think when a template tries to render null, it should probably render the text null.

Here's an example of it causing problems:

playframework/playframework#2802

Allow per-package template imports

I have a multiple view sets (for example, one view set for website, and one view set for admin panel of it), and they need some common imports (custom template magic) and some imports specific to the set. Currently Twirl has no way to specify a scoped import, so there is a suggestion to introduce one.

Currently I have three ideas on how to implement it:

  1. Add some format to import string, like some.helpers._ @ some.views._, so first part is import itself, and second part is a scope of that import. It will not break any existing imports, but it's a dirty way, I think.
  2. Create structure like case class TemplateImport(import: String, scope: String) and specify it either explicitly, or like SBT dependencies, provide an implicit conversion from string like "helpers._" % "views._". It possibly can break existing imports, because there is a chance that this implicit conversion will be out of scope in build.sbt, but is a clean way.
  3. Move imports out of build.sbt file (while retaining key templateImports for compatibility, but making it deprecated). For example, there can be file like _imports.scala.html that will hold imports in a Twirl usual format for that package and all descedants. Will not break anything if we keep old key, but it's the most hard way.

I can implement this feature itself, but I think that it should be discussed before I implement it.

Unused import

I have "-Xfatal-warnings", "-Ywarn-unused-import", in my scalacOptions

I cannot use twirl

import play.twirl.api._
import play.twirl.api.TemplateMagic._

class error extends BaseScalaTemplate[play.twirl.api.HtmlFormat.Appendable,Format[play.twirl.api.HtmlFormat.Appendable]](play.twirl.api$

[play-2.3.0-RC1] Template compilation crashes when parameter type not defined

When compiling a template that uses an unknown type as a parameter, the template compiler crashes with an IndexOutOfBoundsException (see below).

How to reproduce:
Create a file foo.scala.html with the following content:

@(foo: Foo)

(the type Foo should not exist)

When compiling this template, the following exception is thrown:

[error] uncaught exception during compilation: java.lang.IndexOutOfBoundsException
java.lang.IndexOutOfBoundsException: -1
    at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:52)
    at scala.collection.immutable.List.apply(List.scala:84)
    at play.twirl.sbt.TemplateProblem$TemplatePosition$.apply(TemplateProblem.scala:46)
    at play.twirl.sbt.TemplateProblem$$anonfun$3$$anonfun$apply$1.applyOrElse(TemplateProblem.scala:14)
    at play.twirl.sbt.TemplateProblem$$anonfun$3$$anonfun$apply$1.applyOrElse(TemplateProblem.scala:13)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
    at scala.Option.collect(Option.scala:250)
    at play.twirl.sbt.TemplateProblem$$anonfun$3.apply(TemplateProblem.scala:13)
    at play.twirl.sbt.TemplateProblem$$anonfun$3.apply(TemplateProblem.scala:12)
    at sbt.Compiler$$anonfun$foldMappers$2$$anonfun$apply$1.apply(Compiler.scala:79)
    at sbt.LoggerReporter.log(LoggerReporter.scala:119)
    at xsbt.DelegatingReporter.info0(DelegatingReporter.scala:42)
    at scala.tools.nsc.reporters.Reporter$$anonfun$error$1.apply$mcV$sp(Reporter.scala:70)
    at scala.tools.nsc.reporters.Reporter$$anonfun$error$1.apply(Reporter.scala:70)
    at scala.tools.nsc.reporters.Reporter$$anonfun$error$1.apply(Reporter.scala:70)
    at scala.tools.nsc.reporters.Reporter.withoutTruncating(Reporter.scala:42)
    at scala.tools.nsc.reporters.Reporter.error(Reporter.scala:70)
    at scala.tools.nsc.CompilationUnits$CompilationUnit.error(CompilationUnits.scala:102)
    at scala.tools.nsc.typechecker.Contexts$Context.scala$tools$nsc$typechecker$Contexts$Context$$unitError(Contexts.scala:390)
    at scala.tools.nsc.typechecker.Contexts$Context$$anonfun$issue$1.applyOrElse(Contexts.scala:402)
    at scala.tools.nsc.typechecker.Contexts$Context$$anonfun$issue$1.applyOrElse(Contexts.scala:401)
    at scala.runtime.AbstractPartialFunction$mcVL$sp.apply$mcVL$sp(AbstractPartialFunction.scala:33)
    at scala.runtime.AbstractPartialFunction$mcVL$sp.apply(AbstractPartialFunction.scala:33)
    at scala.runtime.AbstractPartialFunction$mcVL$sp.apply(AbstractPartialFunction.scala:25)
    at scala.tools.nsc.typechecker.Contexts$Context.issue(Contexts.scala:401)
    at scala.tools.nsc.typechecker.Typers$Typer.typedIdent$2(Typers.scala:5181)
    at scala.tools.nsc.typechecker.Typers$Typer.typedIdentOrWildcard$1(Typers.scala:5218)
    at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5561)
    at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5642)
    at scala.tools.nsc.typechecker.Typers$Typer.typedType(Typers.scala:5769)
    at scala.tools.nsc.typechecker.Typers$Typer.typedHigherKindedType(Typers.scala:5776)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$107.apply(Typers.scala:5259)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$107.apply(Typers.scala:5257)
    at scala.reflect.internal.Types$class.map2Conserve(Types.scala:6400)
    at scala.reflect.internal.SymbolTable.map2Conserve(SymbolTable.scala:13)
    at scala.tools.nsc.typechecker.Typers$Typer.typedAppliedTypeTree$1(Typers.scala:5257)
    at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5573)
    at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5642)
    at scala.tools.nsc.typechecker.Typers$Typer.typedType(Typers.scala:5769)
    at scala.tools.nsc.typechecker.Typers$Typer.typedType(Typers.scala:5772)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:1529)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$20.apply(Typers.scala:1529)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
    at scala.collection.AbstractTraversable.map(Traversable.scala:105)
    at scala.tools.nsc.typechecker.Typers$Typer.parentTypes(Typers.scala:1529)
    at scala.tools.nsc.typechecker.Namers$Namer.templateSig(Namers.scala:878)
    at scala.tools.nsc.typechecker.Namers$Namer.moduleSig(Namers.scala:949)
    at scala.tools.nsc.typechecker.Namers$Namer.getSig$1(Namers.scala:1451)
    at scala.tools.nsc.typechecker.Namers$Namer.typeSig(Namers.scala:1466)
    at scala.tools.nsc.typechecker.Namers$Namer$$anonfun$monoTypeCompleter$1$$anonfun$apply$1.apply$mcV$sp(Namers.scala:731)
    at scala.tools.nsc.typechecker.Namers$Namer$$anonfun$monoTypeCompleter$1$$anonfun$apply$1.apply(Namers.scala:730)
    at scala.tools.nsc.typechecker.Namers$Namer$$anonfun$monoTypeCompleter$1$$anonfun$apply$1.apply(Namers.scala:730)
    at scala.tools.nsc.typechecker.Namers$Namer.scala$tools$nsc$typechecker$Namers$Namer$$logAndValidate(Namers.scala:1499)
    at scala.tools.nsc.typechecker.Namers$Namer$$anonfun$monoTypeCompleter$1.apply(Namers.scala:730)
    at scala.tools.nsc.typechecker.Namers$Namer$$anonfun$monoTypeCompleter$1.apply(Namers.scala:729)
    at scala.tools.nsc.typechecker.Namers$$anon$1.completeImpl(Namers.scala:1614)
    at scala.tools.nsc.typechecker.Namers$LockingTypeCompleter$class.complete(Namers.scala:1622)
    at scala.tools.nsc.typechecker.Namers$$anon$1.complete(Namers.scala:1612)
    at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1231)
    at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1374)
    at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5295)
    at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5642)
    at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2928)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$61.apply(Typers.scala:3032)
    at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$61.apply(Typers.scala:3032)
    at scala.collection.immutable.List.loop$1(List.scala:170)
    at scala.collection.immutable.List.mapConserve(List.scala:186)
    at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3032)
    at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5301)
    at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5587)
    at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5642)
    at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5704)
    at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.apply(Analyzer.scala:99)
    at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:464)
    at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
    at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
    at scala.collection.Iterator$class.foreach(Iterator.scala:727)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
    at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.run(Analyzer.scala:91)
    at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1583)
    at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1557)
    at scala.tools.nsc.Global$Run.compileSources(Global.scala:1553)
    at scala.tools.nsc.Global$Run.compile(Global.scala:1662)
    at xsbt.CachedCompiler0.run(CompilerInterface.scala:123)
    at xsbt.CachedCompiler0.run(CompilerInterface.scala:99)
    at xsbt.CompilerInterface.run(CompilerInterface.scala:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:102)
    at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:48)
    at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:41)
    at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply$mcV$sp(AggressiveCompile.scala:99)
    at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply(AggressiveCompile.scala:99)
    at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply(AggressiveCompile.scala:99)
    at sbt.compiler.AggressiveCompile.sbt$compiler$AggressiveCompile$$timed(AggressiveCompile.scala:166)
    at sbt.compiler.AggressiveCompile$$anonfun$3.compileScala$1(AggressiveCompile.scala:98)
    at sbt.compiler.AggressiveCompile$$anonfun$3.apply(AggressiveCompile.scala:143)
    at sbt.compiler.AggressiveCompile$$anonfun$3.apply(AggressiveCompile.scala:87)
    at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:39)
    at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:37)
    at sbt.inc.IncrementalCommon.cycle(Incremental.scala:99)
    at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:38)
    at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:37)
    at sbt.inc.Incremental$.manageClassfiles(Incremental.scala:65)
    at sbt.inc.Incremental$.compile(Incremental.scala:37)
    at sbt.inc.IncrementalCompile$.apply(Compile.scala:27)
    at sbt.compiler.AggressiveCompile.compile2(AggressiveCompile.scala:157)
    at sbt.compiler.AggressiveCompile.compile1(AggressiveCompile.scala:71)
    at sbt.compiler.AggressiveCompile.apply(AggressiveCompile.scala:46)
    at sbt.Compiler$.apply(Compiler.scala:75)
    at sbt.Compiler$.apply(Compiler.scala:66)
    at sbt.Defaults$.sbt$Defaults$$compileTaskImpl(Defaults.scala:770)
    at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:762)
    at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:762)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
    at sbt.std.Transform$$anon$4.work(System.scala:64)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
    at sbt.Execute.work(Execute.scala:244)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
[error] (web/compile:compile) java.lang.IndexOutOfBoundsException: -1
[error] Total time: 2 s, completed 18.05.2014 14:16:59

[play-2.3.0-RC1] UTF8 encoded templates not supported

When using UTF8 encoded scala.html template files that contain characters such as €, ö, or ü, it does not compile with the following error:

[error] IO error while decoding path/to/template.scala with UTF-8

Problem happens only when the Java default encoding is not set to UTF8 when launching SBT.

Does not build from clean install?

I just downloaded this on a machine which had it's ~/.ivy2/ folder wiped clean, and it doesn't seem to compile properly. Are we missing an explicit dependency on play? I did nothing but clone and run sbt test

haoyi-mbp:twirl haoyi$ sbt test
[info] FormatSpec
[info]
[info] Formats should
[info] + show null text values as empty
[info]
[info] HtmlFormat should
[info] + escape '<', '&' and '>'
[info] + escape single quotes
[info] + escape double quotes
[info] + not escape non-ASCII characters
[info]
[info] JavaScriptFormat should
[info] + escape ''', '"' and '\'
[info]
[info] Total for specification FormatSpec
[info] Finished in 26 ms
[info] 6 examples, 0 failure, 0 error
[info] Passed: Total 6, Failed 0, Errors 0, Passed 6
[info] Compiling 3 Scala sources to /Users/haoyi/Dropbox (Personal)/Workspace/twirl/compiler/target/scala-2.10/test-classes...
[info] OldParserSpec
[info]
[info] Old twirl parser should
[info]
[info]   succeed for
[info]   + static.scala.html
[info]   + simple.scala.html
[info]   + complicated.scala.html
[info]   + imports.scala.html
[info]   + case.scala.js
[info]
[info]   handle parentheses in string literals
[info]   + with left parenthesis
[info]   + with right parenthesis and '@'
[info]
[info]   fail for
[info]   + unclosedBracket.scala.html
[info]   + unclosedBracket2.scala.html
[info]   + invalidAt.scala.html
[info]
[info] Total for specification OldParserSpec
[info] Finished in 19 ms
[info] 10 examples, 0 failure, 0 error
[info] ParserSpec
[info]
[info] New twirl parser should
[info]
[info]   succeed for
[info]   + static.scala.html
[info]   + simple.scala.html
[info]   + complicated.scala.html
[info]   + imports.scala.html
[info]   + case.scala.js
[info]   + import expressions
[info]
[info]   handle string literals within parentheses
[info]   + with left parenthesis
[info]   + with right parenthesis and '@'
[info]
[info]   fail for
[info]   + unclosedBracket.scala.html
[info]   + unclosedBracket2.scala.html
[info]   + invalidAt.scala.html
[info]
[info] Total for specification ParserSpec
[info] Finished in 19 ms
[info] 11 examples, 0 failure, 0 error
[info] Passed: Total 21, Failed 0, Errors 0, Passed 21
[info] TemplateUtilsSpec
[info]
[info] Templates should
[info] + provide a HASH util
[info]
[info]   provide a Format API
[info]   + HTML for example
[info]   + Text for example
[info]
[info] Total for specification TemplateUtilsSpec
[info] Finished in 18 ms
[info] 3 examples, 0 failure, 0 error
[info] CompilerSpec
[info]
[info] Twirl compiler (with new parser) should
[info] ! compile successfully (real)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5$$anonfun$apply$6.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5$$anonfun$apply$6.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5.apply(CompilerSpec.scala:35)
[info]
[info] ! compile successfully (static)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8$$anonfun$apply$9.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8$$anonfun$apply$9.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8.apply(CompilerSpec.scala:48)
[info]
[info] ! compile successfully (patternMatching)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12$$anonfun$apply$13.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12$$anonfun$apply$13.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12.apply(CompilerSpec.scala:54)
[info]
[info] ! compile successfully (hello)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$16.apply(CompilerSpec.scala:72)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$16.apply(CompilerSpec.scala:70)
[info]
[info] ! compile successfully (helloNull)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$20.apply(CompilerSpec.scala:78)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$20.apply(CompilerSpec.scala:76)
[info]
[info] ! compile successfully (set)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$24.apply(CompilerSpec.scala:84)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$24.apply(CompilerSpec.scala:82)
[info]
[info] ! compile successfully (imports)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$28.apply(CompilerSpec.scala:90)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$28.apply(CompilerSpec.scala:88)
[info]
[info] ! compile successfully (utf8)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$32.apply(CompilerSpec.scala:96)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$32.apply(CompilerSpec.scala:94)
[info]
[info] x fail compilation for error.scala.html
[error]    ko (CompilerSpec.scala:104)
[info]
[info] ! compile templates that have contiguous strings > than 64k
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$39.apply(CompilerSpec.scala:111)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$39.apply(CompilerSpec.scala:108)
[info]
[info] ! allow rendering a template twice
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$42.apply(CompilerSpec.scala:118)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$42.apply(CompilerSpec.scala:116)
[info]
[info]
[info] StringGrouper should
[info] + split before a surrogate pair
[info] + not split a surrogate pair
[info] + split after a surrogate pair
[info]
[info] Total for specification CompilerSpec
[info] Finished in 18 ms
[info] 14 examples, 1 failure, 10 errors
[info] OldParserCompilerSpec
[info]
[info] Twirl compiler (with old parser) should
[info] ! compile successfully (real)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5$$anonfun$apply$6.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5$$anonfun$apply$6.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5.apply(CompilerSpec.scala:37)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$5.apply(CompilerSpec.scala:35)
[info]
[info] ! compile successfully (static)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8$$anonfun$apply$9.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8$$anonfun$apply$9.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8.apply(CompilerSpec.scala:50)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$8.apply(CompilerSpec.scala:48)
[info]
[info] ! compile successfully (patternMatching)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12$$anonfun$apply$13.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12$$anonfun$apply$13.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12.apply(CompilerSpec.scala:57)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$12.apply(CompilerSpec.scala:54)
[info]
[info] ! compile successfully (hello)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$16.apply(CompilerSpec.scala:72)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$16.apply(CompilerSpec.scala:70)
[info]
[info] ! compile successfully (helloNull)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$20.apply(CompilerSpec.scala:78)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$20.apply(CompilerSpec.scala:76)
[info]
[info] ! compile successfully (set)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$24.apply(CompilerSpec.scala:84)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$24.apply(CompilerSpec.scala:82)
[info]
[info] ! compile successfully (imports)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$28.apply(CompilerSpec.scala:90)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$28.apply(CompilerSpec.scala:88)
[info]
[info] ! compile successfully (utf8)
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$32.apply(CompilerSpec.scala:96)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$32.apply(CompilerSpec.scala:94)
[info]
[info] x fail compilation for error.scala.html
[error]    ko (CompilerSpec.scala:104)
[info]
[info] ! compile templates that have contiguous strings > than 64k
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$39.apply(CompilerSpec.scala:111)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$39.apply(CompilerSpec.scala:108)
[info]
[info] ! allow rendering a template twice
[error]    CompilationError: : error: not found: object play  (CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:208)
[error] play.twirl.compiler.test.Helper$CompilerHelper$$anonfun$compile$1.apply(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.Helper$CompilerHelper.compile(CompilerSpec.scala:205)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$42.apply(CompilerSpec.scala:118)
[error] play.twirl.compiler.test.CompilerTests$$anonfun$1$$anonfun$apply$42.apply(CompilerSpec.scala:116)
[info]
[info]
[info] StringGrouper should
[info] + split before a surrogate pair
[info] + not split a surrogate pair
[info] + split after a surrogate pair
[info]
[info] Total for specification OldParserCompilerSpec
[info] Finished in 18 ms
[info] 14 examples, 1 failure, 10 errors
[error] Error: Total 31, Failed 2, Errors 20, Passed 9
[error] Error during tests:
[error]     play.twirl.compiler.test.CompilerSpec
[error]     play.twirl.compiler.test.OldParserCompilerSpec
[error] (compiler/test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 44 s, completed Aug 9, 2014 4:20:09 AM
haoyi-mbp:twirl haoyi$

Document update suggestion about the range of dynamic code block

Hi, I'm noob in using twirl and now learning it from the document.

I found that whitespace concludes the range of dynamic code block specified by '@'.
For example,

@main (menuList)("Liked Posts")    // Incorrect result: It prints 'main' template function as a value
@for (menu <- menuList) { ... }    // Compilation error: It says "'(' expected but ')' found."

above codes don't work and I had to remove whitespaces after '@' like below.

@main(menuList)("Liked Posts")
@for(menu <- menuList) { ... }

How about mentioning the effect of whitespace in Twirl document?
I spent hours to figure out what's wrong and I don't want others to suffer from it.

Update:
I found a similar issue was suggested to play google group 3 years ago.
https://groups.google.com/forum/#!topic/play-framework/8Z_KctGKWm4
if modifying template parser is tough one, I think letting users to know about the restriction is a good alternative.

Support multiline string literals

It appears that the old template compiler supported multiline string literals, while the new one doesn't. typesafe.com uses them. While the use of multiline string literals in a template is somewhat dubious, it's technically a regression.

Newline before case in match expression not properly parsed

@jhaberstro originally filed this bug as playframework/playframework#1318. Moving it here.

In template files, while the following code compiles fine:

@(123) match { case 123 => "test" }

This code does not:

@(123) match {
  case 123 => "test" }

This can be seen in isolation by passing the code string directly to the matchExpression parser combinator. You will see in the first case the AST produced is the following:
Display(ScalaExp(List(Simple((123)), Simple( match), Block( ,Some( case 123 =>),List(Plain( "test" ))))))

but in the later case (formatting here might not capture the newline correctly, but you can still see the incorrect parse nonetheless):
Display(ScalaExp(List(Simple((123)), Simple( match), Block( ,None,List(Plain( case 123 => "test" )))))

[Play 2.5 (Java)] Accessing template object with Class that implements an interface

I have not investigated this very far, but I am receiving compilation errors attempting to access variables set in an interface of an object I pass to a template. Written up example below. Has anyone else seen this issue?

interface AInterface{
   String foo="foo";
}
class superA{
   String superBar="superBar";
}
class A extends superA implements AInterface{
   String bar = "bar";
}

----Inside template-----

@(someVar:A)
This works fine for 'bar': @(someVar.bar)
And this works fine for 'superBar': @(someVar.superBar)

[Compilation error: value name is not a member of class] 
But for 'foo': @(someVar.foo) 

Extended Template: too many arguments for method error

To recreate, download the minimal 2.4.0 Play framework from here:

http://downloads.typesafe.com/typesafe-activator/1.3.4/typesafe-activator-1.3.4-minimal.zip

Create a new Java play app:

$ activator new testapp play-java

Following the directions at the bottom of this document:

https://github.com/playframework/twirl/blob/master/docs/manual/working/javaGuide/main/templates/JavaTemplateUseCases.md

I have an extended template that needs an extra script.

Edit the file index.scala.html so it looks like this:

 @(message: String)

 @scripts = {
     <script type="text/javascript">alert("hello !");</script>
 }

 @main("Welcome to Play",scripts) {

     @play20.welcome(message, style = "Java")

 }

Then compile with activator. This is the output:

[info] Compiling 6 Scala sources and 2 Java sources to /testapp/target/scala-2.11/classes...
[error] /testapp/app/views/index.scala.html:7: too many arguments for method apply: (title: String)(content: play.twirl.api.Html)play.twirl.api.HtmlFormat.Appendable in class main
[error] @main("Welcome to Play",scripts) {
[error] ^
[error] one error found
error Compilation failed

Html.apply should also accept a Option[String]

Hey there,

i found myself recently using very often the following code throughout our template code:

Html(data.textOption.getOrElse(""))

We have lots of texts that are optional and may contain HTML tags. Therefore i find myself often writing the code above. And i thought it would be nice to have something like this out of the box with Twirl.

def apply(text: Option[String]): Html = {
    apply(text.getOrElse(""))
}

What do you think? If you like it, i can open a Pull Request.

Thx!

@import should be valid before the template signature

If @import was valid before the template signature one could have this:

@import org.some.example.package.Customer

@(customer: Customer, orders: List[Order])

<h1>Welcome @customer.name!</h1>
<ul>
@for(order <- orders) {
  <li>@order.title</li>
}
</ul>

Instead of this:

@(customer: org.some.example.package.Customer, orders: List[Order])

@import org.some.example.package.Customer

<h1>Welcome @customer.name!</h1>
<ul>
@for(order <- orders) {
  <li>@order.title</li>
}
</ul>

Allow implicit for twirl variables

I'd like to do something along the lines of:

@(implicit request: spray.routing.RequestContext)
@main(title = "Login") {
  <h1>Login page</h1>   
  <p>
    Select a provider:
    <a href="login/oauth2/github"> <img src="/static/images/providers/github.png"/></a>
    <a href="login/oauth2/facebook"> <img src="/static/images/providers/facebook.png"/></a>
  </p>   
}

Crash when the Scala compiler is installed in a path with spaces in it

See scala-ide/scala-ide-play2#238. Probably Twirl should escape spaces in the returned path.

Stack trace:

Caused by: java.net.URISyntaxException: Illegal character in path at index 66: file:/Volumes/Thunderbolt_SSD/dragos/tmp/eclipse-luna-fresh-no-ide copy/plugins/org.scala-lang.scala-compiler_2.11.4.v20141023-110636-d783face36.jar
    at java.net.URI$Parser.fail(URI.java:2848)
    at java.net.URI$Parser.checkChars(URI.java:3021)
    at java.net.URI$Parser.parseHierarchical(URI.java:3105)
    at java.net.URI$Parser.parse(URI.java:3053)
    at java.net.URI.<init>(URI.java:588)
    at java.net.URL.toURI(URL.java:939)
    at play.twirl.compiler.TwirlCompiler$TemplateAsFunctionCompiler$CompilerInstance.toAbsolutePath$1(TwirlCompiler.scala:454)
    at play.twirl.compiler.TwirlCompiler$TemplateAsFunctionCompiler$CompilerInstance.compiler$lzycompute(TwirlCompiler.scala:455)
    at play.twirl.compiler.TwirlCompiler$TemplateAsFunctionCompiler$CompilerInstance.compiler(TwirlCompiler.scala:445)
    at play.twirl.compiler.TwirlCompiler$TemplateAsFunctionCompiler$PresentationCompiler$.<init>(TwirlCompiler.scala:499)
    at play.twirl.compiler.TwirlCompiler$TemplateAsFunctionCompiler$PresentationCompiler$.<clinit>(TwirlCompiler.scala)
    ... 117 more

Offending code seems to be:

def toAbsolutePath(cs: CodeSource) = new File(cs.getLocation.toURI).getAbsolutePath
val compilerPath = toAbsolutePath(Class.forName("scala.tools.nsc.Interpreter").getProtectionDomain.getCodeSource)

The default, one-arg behaviors for Html default to unsafe behavior.

I was paging through the API this morning and discovered that the Html class contains facilities for escaping text passed into it, but the behavior is opt-in instead of opt out. The one-arg constructors explicitly disable the behavior:

class Html private[api] (elements: immutable.Seq[Html], text: String, escape: Boolean) extends BufferedContent[Html](elements, text) {
  def this(text: String) = this(Nil, Formats.safe(text), false)
  def this(elements: immutable.Seq[Html]) = this(elements, "", false)

This seems like bad practice for library consumers. Is there reasoning why this was done or could this be defaulted to true in a future release?

Compilation error using `if` statement

Following template works:

@(attrs: Seq[(String,String)] = null)
@if(attrs!=null){
    @attrs.map{ v => @v._1 }
}

Removing the newline makes it fail (Not parsed? compilation error):

@(attrs: Seq[(String,String)] = null)
@if(attrs!=null){@attrs.map{ v => @v._1 }}

Maybe #35 is somehow related?

Support for variables

I've seen there was another issue for this (#63) but it's closed and I think it's an important lack.

For now, if we need to declare some variables we have to to this:

@defining(
  myObject.calcFoo,
  myObject.calcBar
  ) { case (foo, bar) =>
 @defining(myObject.calcResult(foo, bar)) { result =>

  … the whole template …

  }
}

And it's not handy. However, we can declare reusable blocks:

@foo = @{myObject.calcFoo}
@bar = @{myObject.calcBar}
@result = @{myObject.calcResult(foo, bar)}

But they are treated as functions, so foo, bar and result will be recalculated every time. I think every time a reusable block is declared without parenthesis, its value should be calculated once and use it as a variable. So the previous example would define variables, and the following one would define functions.

@foo() = @{myObject.calcFoo}
@bar() = @{myObject.calcBar}
@result() = @{myObject.calcResult(foo, bar)}

Why the generated text/html looks wired?

I just used a very simple template below:

https://github.com/llinder/spray-twirl-bootstrap/blob/master/src/main/twirl/index.scala.html

or

<!DOCTYPE html>
<html>
<head>
    <title>Bootstrap 101 Template</title>
    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<h1>Hello, world!</h1>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html> 

The text/html generated by the template looks like:

<!DOCTYPE html>\n<html>\n<head>\n    <title>Bootstrap 101 Template</title>\n    <!-- Bootstrap -->\n    <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\">\n</head>\n<body>\n<h1>Hello, world!</h1>\n<script src=\"http://code.jquery.com/jquery-latest.js\"></script>\n<script src=\"js/bootstrap.min.js\"></script>\n</body>\n</html>

The text/html doesn't display properly in the browser. Any ideas?

Thanks!

Regression since Play 2.2.3: bad parsing of case statements

I have a .scala.html file which contains dynamically generated JavaScript. When I upgrade from Play 2.2.3 to Play 2.3.0-RC2 with Twirl it fails because it finds the text "case" on the page. E.g. this page works with Play 2.2.3, but not Twirl:

@()

var varName = "ben";    
switch (varName) {
   case "larry": 
       alert('Hey');
       break;
   default: 
       alert('hello world');
       break;
}

In the documentation there's an example of a case statement. In this example, there's an "@var match {" which comes first. I would expect "case" should not be handled unless it's in such a context.

Make multiple argument lists useful

The only situation where you really need multiple argument lists is for path-dependent argument types but this breaks Twirl's translation scheme because argument lists have to merged to implement play.twirl.api.TemplateX. An obvious fix would be not to extend a TemplateX class or generate a render method when multiple argument lists are used.

[Play 2.3.8] If condition bring line feed in scala template

Hi all,

I am facing issue with if conditions in scala template. In the following circumstance, the html will have white spaces and line breaks in between the two divs.

<div>
    content in previous div.
</div>
@if(condition) {
    <div>
        content in next div
    </div>

}

Missing SBT settings

It took me a while and lots of wasted SBT contortions to find out that my project's settings required the addition of SbtTwirl.projectSettings, SBT 0.13.5-RC2.

Shouldn't this be mentioned on the readme?

Pattern matching is limited or not working properly in Scala templates

@almeidap originally filed as playframework/playframework#1164. Moving here.

Seems that this issue has been forgotten as per Lighthouse ticket here: http://play.lighthouseapp.com/projects/82401/tickets/741-improper-compilation-of-match-case-constructs-in-templates

Using Play 2.1.2-RC1, I'm still not able to use complex pattern matching properly in Scala templates, e.g.:

@group.users match {
    case Some(users) if !users.isEmpty => {
        @for(user <- users) {
            <div class="row">
                <div class="span1">
                    @user.avatarUrl.map { avatarUrl =>
                        <img src="@avatarUrl" class="avatar img-polaroid" title="@user.name" alt="@user.name" />
                    }
                </div>
                <div class="span3">
                    <h3>@user.name</a></h3>
                </div>
            </div>
        }
    }
    case _ => @noResults()
}

Putting the first case statement at the same line of match statement, using @case or wrapping Html units with @{...} always leads to compilation failure or not evaluated expressions.

Thanks!

A Set[play.twirl.api.Html] allows repeated elements

scala> import scala.collection.immutable.Set
import scala.collection.immutable.Set

scala> Set(Html("<h1>teste</h1>"), Html("<h1>teste</h1>"))
res0: scala.collection.immutable.Set[play.twirl.api.Html] = Set(<h1>teste</h1>, <h1>teste</h1>)

scala> Set("<h1>teste</h1>", "<h1>teste</h1>")
res1: scala.collection.immutable.Set[String] = Set(<h1>teste</h1>)

If the class Html would implement hashCode and equals this problem would be fixed. These methods could delegate to toString.equals and toString.hashCode. However I have no ideia if a performance penalty might be introduced.

Gradle Support

Currently Twirl only works on sbt, is there any work to also have a working gradle/maven plugin?

String interpolation in templates

Currently Twirl does not support string interpolation in templates, I think mostly because simple string interpolation can be done with Twirl itself, like Hello, @name!. But more complex string interpolators cannot be substituted with Twirl. The sample of such interpolator is a translating interpolator at my project, Scalingua. Currently we have to write

  @(t"Hello, world!")

Could Twirl compiler support shorter and cleaner version of it, something like

  @t"Hello, world!"

This is a pretty minor issue, of course, but these parentheses looks ugly, and adding string interpolation syntax should not break any existing code.

enablePlugins(var) need import something

we have more project .we need import play.twirl.sbt._ in porject build file.

someproject.enablePlugins(SbtTwirl) or
someproject.enablePlugins(play.twirl.sbt.SbtTwirl )

Surprising behavior with Appendable subclasses.

This is a custom format that escapes | as bar.

src/main/scala/example/Example.scala

package example

import play.twirl.api._
import scala.collection.immutable

sealed trait Example extends Appendable[Example] {
  val contentType = "text/example"

  def appendTo(sb: StringBuilder)

  override def toString = {
    val sb = new StringBuilder
    appendTo(sb)
    sb.toString
  }
}

object ExampleFormat extends Format[Example] {
  val empty = raw("")

  def escape(text: String) = raw(text.replace("|", "bar"))

  def fill(elements: immutable.Seq[Example]) = new Example {
    def appendTo(sb: StringBuilder): Unit = elements.foreach(_.appendTo(sb))
  }

  def raw(text: String) = new Example {
    def appendTo(sb: StringBuilder): Unit = sb ++= text
  }
}

src/main/twirl/example/my.ex

@(text: String)

| @text |

The result of example.ex.my("bar") is bar bar bar instead of | bar |.

The template text is unexpectedly being escaped. This is because the runtime type is not Example and https://github.com/playframework/twirl/blob/master/api/src/main/scala/play/twirl/api/BaseScalaTemplate.scala#L20.

This could be improved to be T or a subtype, instead of only T.


(More generally, I feel like the runtime type branching in BaseScalaTemplate could be eliminated.)

Use twirl in spray

Hi,

I'am using twirl in spray and I have one question and one problem:

  1. Twirl creates source file from a template in target/scala-2.10/twirl/main/html/index.template.scala, for example. Is ti possible to change that path?
  2. I've got this error when spray try to return page:

java.lang.StackOverflowError
at scala.collection.mutable.ArrayBuilder.(ArrayBuilder.scala:24)
at scala.collection.mutable.ArrayBuilder$ofRef.(ArrayBuilder.scala:57)
at scala.collection.mutable.ArrayBuilder$.make(ArrayBuilder.scala:49)
at scala.Array$$anon$2.apply(Array.scala:63)
at scala.Array$$anon$2.apply(Array.scala:62)

I have this part in the template:

def apply/1.4/():play.twirl.api.HtmlFormat.Appendable = {
display {

Seq[Any](format.raw/1.6/("""

"""),format.raw/3.3/("""


.....

Thanks

Zlaja

Sbt Setting for package name

I was looking around for some way to set the package name in the build.sbt file instead of having to rely on the file structure of the templates. It would be nice if you could set a package prefix that would be appended to the beginning of the file structure name.

Allow for specifying imports at beginning of templates

Right now you have to specify imports after the template declaration:

@(user: com.example.User)
@import com.example.User
Hello @user.getName()

This seems odd because it's not how Java/Scala classes work and also because it results in much more typing than the alternative:

@import com.example.User
@(user: User)
Hello @user.getName()

I took a stab at implementing this here: playframework/playframework#1661

Cannot get the simplest "Hello World" to work.

TL;DR - https://github.com/reid-spencer/im-going-twirly

I'm working on a project, without Play, that uses Twirl. For some reason I can't get sbt to find the Twirl templates and compile them. I've been after this for many hours, read the docs, read the source code, and still can't figure out why my project doesn't work. I will sincerely appreciate any help in either pointing out my error, fixing the bug in Twirl, or at least making the correct magic incantation clearer in the document.

Basically, I have a "HelloWorld" that looks like this:

package com.example

import _root_.com.example.txt.hello_world

object Hello {
  def main(args: Array[String]): Unit = {
    println(hello_world(args))
  }
}

And, as you might infer, there should be a Twirl template at com.example.hello_world.scala.txt. There is and it looks like this:

@(args: Array[String])
Hello, world. There are @{args.length} arguments. 

That's it. That's all the source code except for the build project.

When I compile the project, I get this:

> compile
[info] Updating {file:/Users/reidspencer/Code/im-going-twirly/}twirl-bug...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/reidspencer/Code/im-going-twirly/target/scala-2.10/classes...
[error] /Users/reidspencer/Code/im-going-twirly/src/main/scala/com/example/Hello.scala:3: object txt is not a member of package com.example
[error] import _root_.com.example.txt.hello_world
[error]                           ^
[error] /Users/reidspencer/Code/im-going-twirly/src/main/scala/com/example/Hello.scala:7: not found: value hello_world
[error]     println(hello_world(args))
[error]             ^
[error] two errors found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Nov 16, 2014 8:20:49 PM

Here's my plugins.sbt:

scalaVersion := "2.10.4"

scalacOptions ++= Seq("-deprecation", "-unchecked", "-feature", "-Xlint")

// To get more information during initialization
logLevel := Level.Debug

// The Typesafe repository
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"

addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.0.3")

And, here's my Build.scala:

import play.twirl.sbt.Import.TwirlKeys
import sbt.Keys._
import sbt._
import play.twirl.sbt.SbtTwirl

object Build extends Build {

  lazy val our_settings : Seq[Setting[_]] = Seq(
    name := "im-going-twirly",
    version := "1.0",
    scalaVersion := "2.11.4",
    libraryDependencies += "org.scalatest" %% "scalatest" % "2.1.6" % "test",
    libraryDependencies += "com.typesafe.play" %% "twirl-api" % "1.0.3",
    sourceDirectories in TwirlKeys.compileTemplates := (unmanagedSourceDirectories in Compile).value
  )

  lazy val project = Project("im-going-twirly", file("."))
    .enablePlugins(SbtTwirl)
    .settings(settings:_*)

  override def rootProject = Some(project)
}

I thought this would be all too simple to fail but it eludes me.

Thanks in advance for any time you spend on it.

Race condition in Scala IDE while using a *.scala.html template

The full error is reported at scala-ide/scala-ide-play2#220 but it is not a problem in Scala IDE. twirl also accesses the presentation compiler but it doesn't do it right.

The problem occurs in this line: https://github.com/playframework/twirl/blob/1.0.x/compiler/src/main/scala/play/twirl/compiler/TwirlCompiler.scala#L410

The origin of this problem lies some lines earlier:

val params = findSignature(
  PresentationCompiler.treeFrom("object FT { def signature" + signature + " }")).get.vparamss

get returns an unsafe instance, it has to be accessed on the PC thread.

no type arguments for views?

@refried originally filed as playframework/playframework#2194. migrating it here

views/foo1.scala.txt (won't compile)

@[L<:shapeless.Nat:shapeless.ops.nat.ToInt](bar: Bar[L])

@bar has size @shapeless.Nat.toInt[L]

views/foo2.scala.txt (will compile, but silly!)

@(bar: Bar[_<:shapeless.Nat], size: Int)

@bar has size @size

controllers/Application.scala

package controllers

import play.api._
import play.api.mvc._
import shapeless.Nat
import shapeless.ops.nat.ToInt

class Bar[L<:Nat]

object Application extends Controller {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  // won't compile
  def foo1 = views.txt.foo1(new Bar[Nat._3])

  // needlessly complicated
  def foo2 = {
    def barSize[L<:Nat:ToInt](bar: Bar[L]): Int = Nat.toInt[L]
    val bar = new Bar[Nat._3]
    val size = barSize(bar)
    views.txt.foo2(bar, size)
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.