├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── build.sh ├── org.scala-ide.play2.feature ├── .project ├── build.properties ├── feature.xml └── pom.xml ├── org.scala-ide.play2.source.feature ├── .project ├── build.properties ├── feature.xml └── pom.xml ├── org.scala-ide.play2.templates ├── .classpath ├── .project ├── META-INF │ └── MANIFEST.MF ├── build.properties ├── plugin.xml ├── pom.xml └── src │ └── org │ └── scalaide │ └── play2 │ └── templates │ ├── Activator.scala │ ├── MasterProjectionDocumentProvider.scala │ ├── TemplateCompiler.scala │ ├── TemplateGeneratedSource.scala │ ├── TemplateParser.scala │ └── TemplateProcessing.scala ├── org.scala-ide.play2.tests ├── .classpath ├── .project ├── META-INF │ └── MANIFEST.MF ├── build.properties ├── pom.xml ├── src │ └── org │ │ └── scalaide │ │ └── play2 │ │ ├── RouteTestSuite.scala │ │ ├── TemplateTestSuite.scala │ │ ├── TestSuite.scala │ │ ├── indenter │ │ └── TemplateAutoIndentTest.scala │ │ ├── lexical │ │ └── PlayDocumentPartitionerTests.scala │ │ ├── quickassist │ │ ├── ControllerMethodTest.scala │ │ └── ResolverTest.scala │ │ ├── routeeditor │ │ ├── RouteActionTest.scala │ │ ├── RouteTest.scala │ │ ├── RouteUriTest.scala │ │ ├── completion │ │ │ ├── ActionContentAssistProcessorTest.scala │ │ │ ├── CompletionComputerTest.scala │ │ │ ├── HttpMethodCompletionComputerTest.scala │ │ │ └── UriCompletionComputerTest.scala │ │ ├── handlers │ │ │ └── LocalRenameTest.scala │ │ ├── hyperlink │ │ │ ├── MethodFinderTest.scala │ │ │ └── RouteHyperlinkDetectorTest.scala │ │ └── lexical │ │ │ ├── AbstractRouteScannerTest.scala │ │ │ ├── RouteActionScannerTest.scala │ │ │ ├── RoutePartitionTokeniserTest.scala │ │ │ └── RouteURIScannerTest.scala │ │ └── templateeditor │ │ ├── BeforeAfterTemplateVersion.scala │ │ ├── lexical │ │ ├── TemplateCompilationUnitTest.scala │ │ └── TemplatePartitionTokniserTest.scala │ │ └── sse │ │ ├── TemplateContentDescriberTest.scala │ │ └── lexical │ │ └── TemplateRegionParserTest.scala └── test-workspace │ ├── .gitignore │ ├── aProject │ ├── .classpath │ ├── .project │ ├── app │ │ └── views │ │ │ ├── index.scala.html │ │ │ ├── scala_compiler_error.scala.html │ │ │ ├── template_parse_error.scala.html │ │ │ └── template_unclosed_comment.scala.html │ ├── moreviews │ │ └── more.scala.html │ ├── route │ └── src │ │ └── org │ │ └── example │ │ ├── JavaClass.java │ │ └── ScalaClass.scala │ ├── resolver │ ├── .classpath │ ├── .project │ ├── app │ │ └── controllers │ │ │ ├── Application.scala │ │ │ ├── JavaApplication.java │ │ │ ├── JavaNonController.java │ │ │ └── NonController.scala │ └── src │ │ └── play │ │ ├── api │ │ └── mvc │ │ │ ├── Action.scala │ │ │ └── EssentialAction.scala │ │ └── mvc │ │ ├── Controller.java │ │ └── Result.java │ ├── routeActionCompletions │ ├── .classpath │ ├── .project │ ├── app │ │ ├── RootScalaApplication.scala │ │ ├── RootStaticJavaApplication.java │ │ ├── ScalaPackage │ │ │ └── package.scala │ │ └── controllers │ │ │ ├── java │ │ │ ├── AbstractApplication.java │ │ │ ├── Application.java │ │ │ ├── InterfaceApplication.java │ │ │ └── SubApplication.java │ │ │ ├── scala │ │ │ ├── AbstractApp.scala │ │ │ ├── ActionWithMangledName.scala │ │ │ ├── AppClass.scala │ │ │ ├── AppNotExtendingController.scala │ │ │ ├── MembersVisibility.scala │ │ │ ├── SubAppClass.scala │ │ │ ├── TraitApp.scala │ │ │ └── empty │ │ │ │ └── Empty │ │ │ └── simple │ │ │ └── SimpleScalaPlayApp.scala │ └── src │ │ └── play │ │ ├── api │ │ └── mvc │ │ │ ├── Action.scala │ │ │ └── EssentialAction.scala │ │ └── mvc │ │ ├── Controller.java │ │ └── Result.java │ └── routeHyperlink │ ├── .classpath │ ├── .project │ └── app │ ├── controllers │ ├── JavaApplication.java │ └── ScalaApplication.scala │ └── model │ └── Element.scala ├── org.scala-ide.play2.update-site ├── .project ├── pom.xml └── site.xml ├── org.scala-ide.play2 ├── .classpath ├── .project ├── META-INF │ └── MANIFEST.MF ├── about.ini ├── about.png ├── build.properties ├── icons │ ├── newtemplate.png │ ├── pin.png │ ├── play.png │ ├── routes.png │ ├── sample.gif │ └── web.png ├── plugin.properties ├── plugin.xml ├── pom.xml ├── schema │ └── template.processing.exsd └── src │ └── org │ └── scalaide │ └── play2 │ ├── IssueTracker.scala │ ├── PlayClassNames.scala │ ├── PlayPlugin.scala │ ├── PlayProject.scala │ ├── lexical │ ├── PlayDocumentPartitioner.scala │ └── PlayPartitionTokeniser.scala │ ├── properties │ ├── PlayPreferences.scala │ ├── PreferenceInitializer.scala │ └── ProjectPropertyPage.scala │ ├── quickassist │ ├── AddRouteEntryProposal.scala │ ├── AddRouteEntryScala.scala │ ├── ControllerMethod.scala │ └── ControllerMethodResolver.scala │ ├── routeeditor │ ├── EditorMessages.properties │ ├── EditorMessages.scala │ ├── HasScalaProject.scala │ ├── RouteAction.scala │ ├── RouteConfiguration.scala │ ├── RouteDocumentProvider.scala │ ├── RouteDoubleClickStrategy.scala │ ├── RouteEditor.scala │ ├── RoutePresentationReconciler.scala │ ├── RouteSyntaxClasses.scala │ ├── RouteUri.scala │ ├── completion │ │ ├── ActionContentAssistProcessor.scala │ │ ├── HttpMethodsCompletionComputer.scala │ │ ├── UriCompletionComputer.scala │ │ └── action │ │ │ ├── ActionCompletionComputer.scala │ │ │ ├── ActionCompletionProposal.scala │ │ │ ├── ActionRouteInput.scala │ │ │ └── MembersComputer.scala │ ├── formatter │ │ └── RouteFormattingStrategy.scala │ ├── handlers │ │ ├── Format.scala │ │ └── LocalRename.scala │ ├── hyperlink │ │ ├── MethodFinder.scala │ │ ├── MethodSearchRequestor.scala │ │ ├── RouteHyperlinkComputer.scala │ │ └── RouteHyperlinkDetector.scala │ ├── lexical │ │ ├── AbstractRouteScanner.scala │ │ ├── HTTPKeywords.scala │ │ ├── MethodPackageRule.scala │ │ ├── RouteActionScanner.scala │ │ ├── RouteDocumentPartitioner.scala │ │ ├── RoutePartitionTokeniser.scala │ │ ├── RoutePartitions.scala │ │ └── RouteURIScanner.scala │ └── properties │ │ ├── RouteColorPreferenceInitializer.scala │ │ ├── RouteFormatterPreferencePage.scala │ │ ├── RoutePreviewerFactoryConfiguration.scala │ │ └── RouteSyntaxColoringPreferencePage.scala │ ├── templateeditor │ ├── BracketAutoEditStrategy.scala │ ├── TemplateAutoIndentStrategy.scala │ ├── TemplateCompilationUnit.scala │ ├── TemplateConfiguration.scala │ ├── TemplateDocumentProvider.scala │ ├── TemplateEditor.scala │ ├── TemplateSyntaxClasses.scala │ ├── compiler │ │ └── CompilerUsing.scala │ ├── completion │ │ └── CompletionProposalComputer.scala │ ├── hyperlink │ │ ├── LocalTemplateHyperlinkComputer.scala │ │ └── TemplateDeclarationHyperlinkDetector.scala │ ├── lexical │ │ ├── HtmlTagScanner.scala │ │ ├── TemplateDefaultScanner.scala │ │ ├── TemplateDocumentPartitioner.scala │ │ ├── TemplateParsing.scala │ │ ├── TemplatePartitionTokeniser.scala │ │ └── TemplatePartitions.scala │ ├── processing │ │ ├── TemplateProcessing.scala │ │ ├── TemplateProcessingProvider.scala │ │ ├── TemplateVersionExhibitor.scala │ │ └── TemplateVersionExtractor.scala │ ├── properties │ │ ├── TemplateColorPreferenceInitializer.scala │ │ ├── TemplatePreviewerFactoryConfiguration.scala │ │ └── TemplateSyntaxColoringPreferencePage.scala │ ├── reconciler │ │ └── TemplateReconcilingStrategy.scala │ └── sse │ │ ├── ContentTypeIdForScala.scala │ │ ├── TemplateActionContributor.scala │ │ ├── TemplateContentDescriber.scala │ │ ├── TemplateStructuredEditor.scala │ │ ├── TemplateStructuredTextViewerConfiguration.scala │ │ ├── hyperlink │ │ └── StructuredTemplateDeclarationHyperlinkDetector.scala │ │ ├── lexical │ │ ├── PartitionHelpers.scala │ │ ├── TemplateRegionParser.scala │ │ ├── TemplateStructuredTextPartitioner.scala │ │ └── TemplateTextRegion.scala │ │ ├── model │ │ ├── TemplateAdapterFactoryProvider.scala │ │ ├── TemplateDocumentLoader.scala │ │ ├── TemplateModelHandler.scala │ │ ├── TemplateStructureDocument.scala │ │ └── TemplateStructuredModel.scala │ │ ├── style │ │ └── ScalaLineStyleProvider.scala │ │ └── validation │ │ └── ScalaSourceValidator.scala │ ├── util │ ├── Debugger.scala │ ├── Images.scala │ ├── Play2PropertyTester.scala │ ├── StoredEditorUtils.scala │ └── SyncedScopedPreferenceStore.scala │ └── wizards │ ├── NewTemplateWizard.scala │ └── NewTemplateWizardPage.scala └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .cache* 2 | target/ 3 | .settings/ 4 | .target/ 5 | .worksheet/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scala IDE plugin for Play 2.x 2 | 3 | This is an extension to Scala IDE to support Play 2.x routes and template files. 4 | 5 | For user documentation, check the [wiki](https://github.com/scala-ide/scala-ide-play2/wiki). 6 | 7 | ## Project structure 8 | 9 | The project is composed of 5 Eclipse plugins: 10 | 11 | * the core plugin 12 | * the test plugin 13 | * an Eclipse feature 14 | * an Eclipse source feature 15 | * an Eclipse update-site 16 | 17 | The projects can be imported inside Scala IDE. And they are fully configured to be compiled with maven and tycho. 18 | 19 | ## Build 20 | 21 | Simply run the ``./build.sh`` script. 22 | 23 | The build is based on 24 | [plugin-profiles](https://github.com/scala-ide/plugin-profiles) and 25 | can be built against several versions of the IDE and Eclipse. 26 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mvn -Peclipse-luna -Pscala-ide-nightly -Pscala-2.11.x clean verify 4 | -------------------------------------------------------------------------------- /org.scala-ide.play2.feature/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2.feature 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.pde.FeatureBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.pde.FeatureNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /org.scala-ide.play2.feature/build.properties: -------------------------------------------------------------------------------- 1 | bin.includes = feature.xml 2 | -------------------------------------------------------------------------------- /org.scala-ide.play2.feature/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.scala-ide 7 | org.scala-ide.play2.build 8 | 0.11.0-SNAPSHOT 9 | 10 | org.scala-ide.play2.feature 11 | eclipse-feature 12 | 13 | -------------------------------------------------------------------------------- /org.scala-ide.play2.source.feature/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2.source.feature 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.pde.FeatureBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.pde.FeatureNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /org.scala-ide.play2.source.feature/build.properties: -------------------------------------------------------------------------------- 1 | bin.includes = \ 2 | feature.xml 3 | -------------------------------------------------------------------------------- /org.scala-ide.play2.source.feature/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.scala-ide 6 | org.scala-ide.play2.build 7 | 0.11.0-SNAPSHOT 8 | 9 | org.scala-ide.play2.source.feature 10 | eclipse-feature 11 | 12 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2.templates24 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.pde.ManifestBuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.SchemaBuilder 15 | 16 | 17 | 18 | 19 | org.scala-ide.sdt.core.scalabuilder 20 | 21 | 22 | 23 | 24 | 25 | org.scala-ide.sdt.core.scalanature 26 | org.eclipse.pde.PluginNature 27 | org.eclipse.jdt.core.javanature 28 | 29 | 30 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Twirl Templates for Play 2.6 4 | Bundle-SymbolicName: org.scala-ide.play2.templates;singleton:=true 5 | Bundle-Version: 0.11.0.qualifier 6 | Bundle-Activator: org.scalaide.play2.templates.Activator 7 | Require-Bundle: org.eclipse.core.runtime, 8 | org.scala-lang.scala-library;bundle-version="[2.12,2.13)", 9 | org.scala-lang.scala-compiler;bundle-version="[2.12,2.13)", 10 | org.scala-lang.scala-reflect;bundle-version="[2.12,2.13)", 11 | org.scala-lang.modules.scala-xml, 12 | org.scala-lang.modules.scala-parser-combinators, 13 | org.scala-ide.play2;bundle-version="[0.11,0.12)", 14 | org.scala-lang.scala-library 15 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 16 | Bundle-ActivationPolicy: lazy 17 | Bundle-ClassPath: ., 18 | target/lib/twirl-compiler.jar, 19 | target/lib/twirl-parser.jar 20 | Import-Package: 21 | com.ibm.icu.text;apply-aspects:=false;org.eclipse.swt.graphics;apply-aspects:=false, 22 | scala.tools.eclipse.contribution.weaving.jdt.ui.javaeditor.formatter;apply-aspects:=false, 23 | scala.tools.eclipse.contribution.weaving.jdt.ui.document;apply-aspects:=false, 24 | org.eclipse.jface.text, 25 | org.eclipse.jface.text.projection, 26 | scala.xml, 27 | scala.util.parsing.input, 28 | scala.reflect.internal.util 29 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = target/classes 3 | bin.includes = plugin.xml,\ 4 | META-INF/,\ 5 | .,\ 6 | *.xml,\ 7 | target/lib,\ 8 | target/lib/twirl-compiler.jar,\ 9 | target/lib/twirl-parser.jar 10 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.scala-ide 5 | org.scala-ide.play2.build 6 | 0.11.0-SNAPSHOT 7 | 8 | org.scala-ide.play2.templates 9 | 0.11.0-SNAPSHOT 10 | eclipse-plugin 11 | 12 | 13 | 14 | com.typesafe.play 15 | ${twirl-compiler.artifactId} 16 | ${twirl.version} 17 | sources 18 | 19 | 20 | com.typesafe.play 21 | ${twirl-parser.artifactId} 22 | ${twirl.version} 23 | sources 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-dependency-plugin 33 | 34 | 35 | copy 36 | initialize 37 | 38 | copy 39 | 40 | 41 | 42 | 43 | com.typesafe.play 44 | ${twirl-compiler.artifactId} 45 | twirl-compiler.jar 46 | 47 | 48 | com.typesafe.play 49 | ${twirl-parser.artifactId} 50 | twirl-parser.jar 51 | 52 | 53 | true 54 | ${project.build.directory}/lib 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/src/org/scalaide/play2/templates/Activator.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templates 2 | 3 | import org.osgi.framework.BundleActivator 4 | import org.osgi.framework.BundleContext 5 | 6 | object Activator { 7 | @volatile 8 | private var context: BundleContext = _ 9 | 10 | def getContext: BundleContext = context 11 | } 12 | 13 | class Activator extends BundleActivator { 14 | 15 | override def start(bundleContext: BundleContext): Unit = 16 | Activator.context = bundleContext 17 | 18 | override def stop(bundleContext: BundleContext): Unit = 19 | Activator.context = null 20 | 21 | } 22 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/src/org/scalaide/play2/templates/MasterProjectionDocumentProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templates 2 | 3 | import scala.tools.eclipse.contribution.weaving.jdt.ui.document.IMasterProjectionDocumentProvider 4 | import org.eclipse.jface.text.IDocument 5 | import org.scalaide.play2.templateeditor.sse.model.TemplateStructuredDocument 6 | 7 | class MasterProjectionDocumentProvider extends IMasterProjectionDocumentProvider { 8 | override def extractActualMaster(master: IDocument) = master match { 9 | case master @ TemplateStructuredDocument(_, _) => master.delegate 10 | case _ => master 11 | } 12 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/src/org/scalaide/play2/templates/TemplateCompiler.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templates 2 | 3 | import java.io.File 4 | 5 | import scala.util.Failure 6 | import scala.util.Try 7 | 8 | import org.scalaide.play2.properties.PlayPreferences 9 | import org.scalaide.play2.templateeditor.compiler.PositionHelper 10 | import org.scalaide.play2.templateeditor.compiler.TemplateToScalaCompilationError 11 | import org.scalaide.play2.templateeditor.processing.GeneratedSource 12 | 13 | import play.twirl.compiler.TemplateCompilationError 14 | import play.twirl.compiler.TwirlCompiler 15 | 16 | object TemplateCompiler { 17 | private val templateCompiler = TwirlCompiler 18 | 19 | def compile(content: String, source: File, sourceDirectory: File, additionalImports: String, inclusiveDot: Boolean): Try[GeneratedSource] = 20 | Try { 21 | templateCompiler.compileVirtual( 22 | content, 23 | source, 24 | sourceDirectory, 25 | "Html", 26 | "HtmlFormat", 27 | PlayPreferences.deserializeImports(additionalImports), 28 | inclusiveDot = inclusiveDot) 29 | } map { 30 | TemplateGeneratedSource 31 | } recoverWith { 32 | case TemplateCompilationError(source, message, line, column) => 33 | val offset = PositionHelper.convertLineColumnToOffset(content, line, column) 34 | Failure(TemplateToScalaCompilationError(source, message, offset, line, column)) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/src/org/scalaide/play2/templates/TemplateGeneratedSource.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templates 2 | 3 | import org.scalaide.play2.templateeditor.processing.GeneratedSource 4 | 5 | import play.twirl.compiler.GeneratedSourceVirtual 6 | 7 | case class TemplateGeneratedSource(wrapped: GeneratedSourceVirtual) extends GeneratedSource { 8 | override def content: String = wrapped.content 9 | override def matrix: Seq[(Int, Int)] = wrapped.matrix 10 | override def mapPosition(generatedPosition: Int): Int = wrapped.mapPosition(generatedPosition) 11 | } 12 | -------------------------------------------------------------------------------- /org.scala-ide.play2.templates/src/org/scalaide/play2/templates/TemplateProcessing.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templates 2 | 3 | import java.io.File 4 | 5 | import scala.io.Codec 6 | import scala.util.Try 7 | import scala.util.parsing.input.Positional 8 | 9 | import org.scalaide.play2.templateeditor.lexical.TemplateParsing.PlayTemplate 10 | import org.scalaide.play2.templateeditor.processing.GeneratedSource 11 | import org.scalaide.play2.templateeditor.processing.{ TemplateProcessing => PlayProcessing } 12 | 13 | class TemplateProcessing extends PlayProcessing { 14 | def compile(content: String, source: File, sourceDirectory: File, additionalImports: String, codec: Codec, inclusiveDot: Boolean): Try[GeneratedSource] = 15 | TemplateCompiler.compile(content, source, sourceDirectory, additionalImports, inclusiveDot) 16 | 17 | def parse(templateCode: String): List[PlayTemplate] = TemplateParser.parse(templateCode) 18 | 19 | def length(input: Positional): Int = TemplateParser.length(input) 20 | } 21 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2.tests 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.scala-ide.sdt.core.scalanature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Scala Plugin (Test) 4 | Bundle-SymbolicName: org.scala-ide.play2.tests 5 | Bundle-Version: 0.11.0.qualifier 6 | Bundle-Vendor: scala-ide.org 7 | Fragment-Host: org.scala-ide.play2 8 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 9 | Require-Bundle: org.scala-lang.scala-library, 10 | org.eclipse.equinox.weaving.aspectj, 11 | org.junit;bundle-version="4.5.0", 12 | org.scala-ide.sdt.core, 13 | org.scala-ide.play2.templates 14 | Import-Package: org.scalaide.core.testsetup, 15 | org.aspectj.weaver.loadtime.definition 16 | Bundle-ClassPath: ., 17 | target/lib/mockito-all-1.9.0.jar, 18 | target/lib/twirl-compiler.jar, 19 | target/lib/twirl-parser.jar 20 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = target/classes/ 3 | bin.includes = META-INF/,\ 4 | test-workspace/,\ 5 | . 6 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.scala-ide 5 | org.scala-ide.play2.build 6 | 0.11.0-SNAPSHOT 7 | 8 | org.scala-ide.play2.tests 9 | eclipse-test-plugin 10 | 11 | 12 | 13 | org.mockito 14 | mockito-all 15 | 16 | 17 | com.typesafe.play 18 | ${twirl-compiler.artifactId} 19 | 20 | 21 | com.typesafe.play 22 | ${twirl-parser.artifactId} 23 | 24 | 25 | 26 | 27 | src 28 | 29 | 30 | org.eclipse.tycho 31 | tycho-surefire-plugin 32 | 33 | ${project.artifactId} 34 | org.scalaide.play2.TestSuite 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-dependency-plugin 41 | 42 | 43 | copy 44 | initialize 45 | 46 | copy 47 | 48 | 49 | 50 | 51 | org.mockito 52 | mockito-all 53 | ${project.build.directory}/lib 54 | 55 | 56 | com.typesafe.play 57 | ${twirl-compiler.artifactId} 58 | twirl-compiler.jar 59 | ${project.build.directory}/lib 60 | 61 | 62 | com.typesafe.play 63 | ${twirl-parser.artifactId} 64 | twirl-parser.jar 65 | ${project.build.directory}/lib 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/RouteTestSuite.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Suite.SuiteClasses 5 | import org.scalaide.play2.routeeditor.hyperlink.RouteHyperlinkDetectorTest 6 | import org.scalaide.play2.routeeditor.hyperlink.MethodFinderTest 7 | import org.scalaide.play2.routeeditor.RouteActionTest 8 | import org.scalaide.play2.routeeditor.completion.HttpMethodCompletionComputerTest 9 | import org.scalaide.play2.routeeditor.lexical.RoutePartitionTokeniserTest 10 | import org.scalaide.play2.routeeditor.completion.UriCompletionComputerTest 11 | import org.scalaide.play2.routeeditor.handlers.LocalRenameTest 12 | import org.scalaide.play2.routeeditor.RouteUriTest 13 | 14 | @RunWith(value=classOf[org.junit.runners.Suite]) 15 | @SuiteClasses(value=Array( 16 | classOf[RouteHyperlinkDetectorTest], 17 | // Test disabled from the test suite as they require UI 18 | // classOf[RouteActionScannerTest], 19 | // classOf[RouteURIScannerTest], 20 | // classOf[RouteScannerTest], 21 | classOf[MethodFinderTest], 22 | classOf[RouteActionTest], 23 | classOf[HttpMethodCompletionComputerTest], 24 | classOf[UriCompletionComputerTest], 25 | classOf[RoutePartitionTokeniserTest], 26 | classOf[LocalRenameTest], 27 | classOf[RouteUriTest])) 28 | class RouteTestSuite { 29 | 30 | } 31 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/TemplateTestSuite.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Suite.SuiteClasses 5 | import org.scalaide.play2.templateeditor.lexical.TemplatePartitionTokeniserTest 6 | import org.scalaide.play2.templateeditor.lexical.TemplateCompilationUnitTest 7 | import org.scalaide.play2.templateeditor.sse.lexical.TemplateRegionParserTest 8 | import org.scalaide.play2.indenter.TemplateAutoIndentTest 9 | import org.scalaide.play2.templateeditor.sse.TemplateContentDescriberTest 10 | @RunWith(value = classOf[org.junit.runners.Suite]) 11 | @SuiteClasses(value = Array( 12 | classOf[TemplateAutoIndentTest], 13 | classOf[TemplatePartitionTokeniserTest], 14 | classOf[TemplateCompilationUnitTest], 15 | classOf[TemplateRegionParserTest], 16 | classOf[TemplateContentDescriberTest])) 17 | class TemplateTestSuite { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/TestSuite.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Suite.SuiteClasses 5 | import org.scalaide.play2.lexical.PlayDocumentPartitionerTests 6 | import org.scalaide.play2.quickassist.ControllerMethodTest 7 | import org.scalaide.play2.quickassist.ResolverTest 8 | import org.scalaide.play2.routeeditor.completion.ActionContentAssistProcessorTest 9 | 10 | @RunWith(value=classOf[org.junit.runners.Suite]) 11 | @SuiteClasses(value=Array( 12 | classOf[RouteTestSuite], 13 | classOf[TemplateTestSuite], 14 | classOf[ControllerMethodTest], 15 | classOf[ActionContentAssistProcessorTest], 16 | classOf[ResolverTest], 17 | classOf[PlayDocumentPartitionerTests] 18 | )) 19 | class TestSuite -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/indenter/TemplateAutoIndentTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.indenter 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.eclipse.jface.text.Document 5 | import org.eclipse.jface.text.DocumentCommand 6 | import org.junit.Assert._ 7 | import org.scalaide.play2.templateeditor.TemplateAutoIndentStrategy 8 | import org.junit.ComparisonFailure 9 | import org.junit.Test 10 | import org.eclipse.jface.text.TextUtilities 11 | 12 | object TemplateAutoIndentTest { 13 | class TestCommand(cOffset: Int, cLength: Int, cText: String, cCaretOffset: Int, cShiftsCaret: Boolean, cDoIt: Boolean) extends DocumentCommand { 14 | caretOffset = cCaretOffset 15 | doit = cDoIt 16 | length = cLength 17 | offset = cOffset 18 | text = cText 19 | shiftsCaret = cShiftsCaret 20 | } 21 | 22 | } 23 | 24 | class TemplateAutoIndentTest { 25 | import TemplateAutoIndentTest._ 26 | 27 | /** Tests if the input string is equal to the expected output, and the 28 | * output caret position is correct. 29 | * 30 | * The '^' character denotes the caret position, both for input and 31 | * expected output. 32 | */ 33 | def test(input: String, expectedOutput: String) { 34 | require(input.count(_ == '^') == 1, "the cursor in the input isn't set correctly") 35 | require(expectedOutput.count(_ == '^') == 1, "the cursor in the expected output isn't set correctly") 36 | 37 | def createDocument(input: String): IDocument = { 38 | val rawInput = input.filterNot(_ == '^') 39 | new Document(rawInput) 40 | } 41 | 42 | val doc = createDocument(input) 43 | 44 | def createTestCommand(input: String): TestCommand = { 45 | val pos = input.indexOf('^') 46 | new TestCommand(pos, 0, TextUtilities.getDefaultLineDelimiter(doc), -1, false, true) 47 | } 48 | 49 | val cmd = createTestCommand(input) 50 | val strategy = new TemplateAutoIndentStrategy(2, useSpacesForTabs = true) 51 | 52 | strategy.customizeDocumentCommand(doc, cmd) 53 | 54 | val m = cmd.getClass.getSuperclass.getDeclaredMethod("execute", classOf[IDocument]) 55 | m.setAccessible(true) 56 | m.invoke(cmd, doc) 57 | 58 | val expected = expectedOutput.replaceAll("\\^", "") 59 | val actual = doc.get() 60 | 61 | if (expected != actual) { 62 | throw new ComparisonFailure("", expected, actual) 63 | } 64 | 65 | assertEquals("Caret position is wrong", cmd.caretOffset, expectedOutput.indexOf('^')) 66 | } 67 | 68 | @Test 69 | def indentPrevLine() { 70 | test( 71 | """ 72 | foo^""", 73 | """ 74 | foo 75 | ^""") 76 | } 77 | 78 | @Test 79 | def indentAfterBrace() { 80 | test( 81 | """ 82 | foo {^""", 83 | """ 84 | foo { 85 | ^""") 86 | } 87 | 88 | @Test 89 | def indentAfterParen() { 90 | test( 91 | """ 92 | foo (^""", 93 | """ 94 | foo ( 95 | ^""") 96 | } 97 | 98 | @Test 99 | def indentAfterBraceWithTail() { 100 | test( 101 | """ 102 | foo { x => ^""", 103 | """ 104 | foo { x => 105 | ^""") 106 | } 107 | 108 | @Test 109 | def indentBetweenBraces() { 110 | test( 111 | """ 112 | foo {^}""", 113 | """ 114 | foo { 115 | ^ 116 | }""") 117 | } 118 | 119 | @Test 120 | def indentBetweenBracesWithTail() { 121 | test( 122 | """ 123 | foo { x => ^}""", 124 | """ 125 | foo { x => 126 | ^ 127 | }""") 128 | } 129 | 130 | @Test 131 | def indentBalancedParens() { 132 | test( 133 | """ 134 | foo { x => x + 1 }^ 135 | """, 136 | """ 137 | foo { x => x + 1 } 138 | ^ 139 | """) 140 | } 141 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/lexical/PlayDocumentPartitionerTests.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.lexical 2 | 3 | import org.eclipse.jface.text.TypedRegion 4 | import org.junit.Assert.assertEquals 5 | import org.junit.Test 6 | import org.scalaide.play2.routeeditor.RouteTest 7 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 8 | 9 | class PlayDocumentPartitionerTests extends RouteTest { 10 | 11 | @Test 12 | def httpToken { 13 | testToken("G%ET / controller", new TypedRegion(0, 3, RoutePartitions.ROUTE_HTTP)) 14 | } 15 | 16 | @Test 17 | def uriToken { 18 | testToken("GET /path/p%ath controller", new TypedRegion(4, 10, RoutePartitions.ROUTE_URI)) 19 | } 20 | 21 | @Test 22 | def actionToken { 23 | testToken("GET / contro%ller", new TypedRegion(6, 10, RoutePartitions.ROUTE_ACTION)) 24 | } 25 | 26 | @Test 27 | def beginningOfFileDefaultToken { 28 | testToken(" % GET / controller", new TypedRegion(0, 2, RoutePartitions.ROUTE_DEFAULT)) 29 | } 30 | 31 | @Test 32 | def endOfFileDefaultToken { 33 | testToken("GET / controller %", new TypedRegion(17, 0, RoutePartitions.ROUTE_DEFAULT)) 34 | } 35 | 36 | @Test 37 | def surroundedDefaultToken { 38 | testToken("GET % / controller", new TypedRegion(3, 3, RoutePartitions.ROUTE_DEFAULT)) 39 | } 40 | 41 | private def testToken(rawContent: String, expectedToken: TypedRegion) = { 42 | val file = RouteFile(rawContent, List('%')) 43 | val caretOffset = file.caretOffset('%') 44 | val partition = file.document.getPartition(caretOffset) 45 | assertEquals("Unexpected token", expectedToken, partition) 46 | } 47 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/quickassist/ControllerMethodTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.quickassist 2 | 3 | import org.junit.Test 4 | import org.junit.Assert 5 | 6 | class ControllerMethodTest { 7 | 8 | @Test 9 | def emptyParamCallSyntax() { 10 | val meth = ControllerMethod("controllers.Application.index", List()) 11 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index()", meth.toRouteCallSyntax) 12 | } 13 | 14 | @Test 15 | def stringParamCallSyntax() { 16 | val meth = ControllerMethod("controllers.Application.index", List(("param1", "String"))) 17 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1)", meth.toRouteCallSyntax) 18 | 19 | val meth1 = ControllerMethod("controllers.Application.index", List(("param1", "java.lang.String"))) 20 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1)", meth1.toRouteCallSyntax) 21 | } 22 | 23 | @Test 24 | def primitiveParamCallSyntax() { 25 | val meth = ControllerMethod("controllers.Application.index", List(("param1", "scala.Long"))) 26 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1: Long)", meth.toRouteCallSyntax) 27 | 28 | val meth1 = ControllerMethod("controllers.Application.index", List(("param1", "Long"))) 29 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1: Long)", meth1.toRouteCallSyntax) 30 | } 31 | 32 | @Test 33 | def primitiveParamCallJavaSyntax() { 34 | val meth = ControllerMethod("controllers.Application.index", List(("param1", "long"))) 35 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1: Long)", meth.toRouteCallSyntax) 36 | 37 | val meth1 = ControllerMethod("controllers.Application.index", List(("param1", "int"))) 38 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1: Int)", meth1.toRouteCallSyntax) 39 | } 40 | 41 | @Test 42 | def primitiveMultipleParamCallSyntax() { 43 | val meth = ControllerMethod("controllers.Application.index", List(("param1", "scala.Long"), ("param2", "Int"), ("param3", "String"))) 44 | Assert.assertEquals("Unexpected routeCallSyntax", "controllers.Application.index(param1: Long, param2: Int, param3)", meth.toRouteCallSyntax) 45 | } 46 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/quickassist/ResolverTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.quickassist 2 | 3 | import org.junit.Test 4 | import org.junit.AfterClass 5 | import org.scalaide.core.testsetup.SDTTestUtils 6 | import org.scalaide.core.testsetup.TestProjectSetup 7 | import org.junit.Assert 8 | 9 | object ResolverTest extends TestProjectSetup("resolver", srcRoot = "/%s/app/", bundleName = "org.scala-ide.play2.tests") { 10 | @AfterClass 11 | def projectCleanUp() { 12 | SDTTestUtils.deleteProjects(project) 13 | } 14 | } 15 | 16 | class ResolverTest { 17 | import ResolverTest._ 18 | import Assert._ 19 | 20 | @Test 21 | def testScalaResolverPos() { 22 | val resolver = new ScalaControllerMethodResolver 23 | 24 | val scu = scalaCompilationUnit("controllers/Application.scala") 25 | val positions = SDTTestUtils.positionsOf(scu.getContents, "/*!*/") 26 | 27 | for (pos <- positions) { 28 | val cm = resolver.getControllerMethod(scu, pos) 29 | assertTrue(s"Could not resolve controller method at position $pos", cm.isDefined) 30 | assertTrue(s"${cm.get} is not in $scalaResolvedMethods", scalaResolvedMethods.contains(cm.get)) 31 | } 32 | } 33 | 34 | @Test 35 | def testScalaResolverNeg() { 36 | val resolver = new ScalaControllerMethodResolver 37 | 38 | val scu = scalaCompilationUnit("controllers/NonController.scala") 39 | val positions = SDTTestUtils.positionsOf(scu.getContents, "/*!*/") 40 | 41 | for (pos <- positions) { 42 | val cm = resolver.getControllerMethod(scu, pos) 43 | assertTrue(s"Wrong controller method (${cm}) at position $pos", cm.isEmpty) 44 | } 45 | } 46 | 47 | @Test 48 | def testJavaResolverPos() { 49 | val resolver = new JavaControllerMethodResolver 50 | val cu = compilationUnit("controllers/JavaApplication.java") 51 | val positions = SDTTestUtils.positionsOf(cu.getBuffer().getCharacters(), "/*!*/") 52 | 53 | for (pos <- positions) { 54 | val cm = resolver.getControllerMethod(cu, pos) 55 | assertTrue(s"Could not resolve controller method at position $pos", cm.isDefined) 56 | assertTrue(s"${cm.get} is not in $javaResolvedMethods", javaResolvedMethods.contains(cm.get)) 57 | } 58 | } 59 | 60 | @Test 61 | def testJavaResolverNeg() { 62 | val resolver = new ScalaControllerMethodResolver 63 | 64 | val scu = compilationUnit("controllers/JavaNonController.java") 65 | val positions = SDTTestUtils.positionsOf(scu.getBuffer().getCharacters(), "/*!*/") 66 | 67 | for (pos <- positions) { 68 | val cm = resolver.getControllerMethod(scu, pos) 69 | assertTrue(s"Wrong controller method (${cm}) at position $pos", cm.isEmpty) 70 | } 71 | } 72 | 73 | private val scalaResolvedMethods = Set( 74 | ControllerMethod("controllers.Application.index", List()), 75 | ControllerMethod("controllers.Application.post", List(("id", "Long"))), 76 | ControllerMethod("controllers.Application.postText", List(("text", "String"), ("id", "Int"))), 77 | ControllerMethod("controllers.Application.internalPostText1", List(("text", "String"), ("id", "Char"))), 78 | ControllerMethod("controllers.Application.internalPostText2", List(("text", "String"), ("id", "Short")))) 79 | 80 | private val javaResolvedMethods = Set( 81 | ControllerMethod("controllers.JavaApplication.index", List()), 82 | ControllerMethod("controllers.JavaApplication.index2", List(("lng", "long"))), 83 | ControllerMethod("controllers.JavaApplication.index3", List(("str", "java.lang.String"), ("id", "int"))), 84 | ControllerMethod("controllers.JavaApplication.index4", List(("f", "java.io.File"), ("id", "int")))) 85 | } 86 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/RouteActionTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.junit.Test 4 | import org.junit.Assert._ 5 | import org.eclipse.jdt.internal.core.util.SimpleDocument 6 | import org.eclipse.jface.text.TypedRegion 7 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 8 | import org.eclipse.jface.text.ITypedRegion 9 | import org.eclipse.jface.text.IDocument 10 | import org.eclipse.jface.text.IRegion 11 | import org.eclipse.jface.text.Region 12 | import org.scalaide.play2.routeeditor.completion.CompletionComputerTest 13 | 14 | object RouteActionTest { 15 | 16 | def actionPartitionOffset(content: String): Int = { 17 | val regex = """\S*\s*/\S*\s*""".r 18 | 19 | regex.findFirstMatchIn(content) match { 20 | case Some(prefix) => 21 | prefix.end 22 | case None => 23 | fail("Unable to partition the test content") 24 | 0 25 | } 26 | 27 | } 28 | 29 | } 30 | 31 | class RouteActionTest extends CompletionComputerTest { 32 | 33 | override protected def createCompletionComputer = ??? 34 | 35 | @Test 36 | def emptyParametersAction() { 37 | 38 | test("GET /path controller.Applic@ation.method()", "controller.Application", "method", Nil) 39 | 40 | } 41 | 42 | @Test 43 | def noParameterAction() { 44 | 45 | test("GET /path controller.Applica@tion.method", "controller.Application", "method", Nil) 46 | 47 | } 48 | 49 | @Test 50 | def actionInt() { 51 | test("GET /path controller.Applicat@ion.method(a: Int)", "controller.Application", "method", List(("a", "Int"))) 52 | } 53 | 54 | @Test 55 | def actionString() { 56 | test("GET /path controller.Application.me@thod(b)", "controller.Application", "method", List(("b", "String"))) 57 | } 58 | 59 | @Test 60 | def actionIntString() { 61 | test("GET /path controller.App@lication.method(c: Int, d)", "controller.Application", "method", List(("c", "Int"), ("d", "String"))) 62 | } 63 | 64 | @Test 65 | def actionStringType() { 66 | test("GET /path controller.Application.method(e,@ f: some.Type)", "controller.Application", "method", List(("e", "String"), ("f", "some.Type"))) 67 | } 68 | 69 | @Test 70 | def discardDefaultValue() { 71 | test("""GET /path controller.Application.me@thod(g ?= "gg", h: Int ?= 3)""", "controller.Application", "method", List(("g", "String"), ("h", "Int"))) 72 | } 73 | 74 | private def test( 75 | documentContent: String, 76 | expectedTypeName: String, 77 | expectedMethodName: String, 78 | expectedParams: List[(String, String)]) { 79 | 80 | val file = new RouteCompletionFile(documentContent) 81 | 82 | val expected = new RouteAction(expectedTypeName, expectedMethodName, expectedParams, file.document.getPartition(file.caretOffset)) 83 | 84 | val actual = RouteAction.routeActionAt(file.document, file.caretOffset) 85 | 86 | compare(expected, actual) 87 | } 88 | 89 | private def compare(expected: RouteAction, actual: Option[RouteAction]) { 90 | actual match { 91 | case Some(action) => 92 | assertEquals("Wrong type", expected.typeName, action.typeName) 93 | assertEquals("Wrong method", expected.methodName, action.methodName) 94 | assertEquals("Wrong parameters", expected.params, action.params) 95 | assertEquals("Wrong region", expected.region, action.region) 96 | case None => 97 | fail("A RouteAction is expected") 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/RouteTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.scalaide.play2.routeeditor.lexical.RouteDocumentPartitioner 4 | import org.eclipse.jface.text.contentassist.ICompletionProposal 5 | import org.eclipse.jface.text.IDocument 6 | import org.junit.Assert._ 7 | import org.eclipse.jface.text.Document 8 | import scala.annotation.tailrec 9 | import org.eclipse.jface.text.IRegion 10 | import org.eclipse.jface.text.Region 11 | import scala.collection.mutable.ListBuffer 12 | import scala.collection.mutable.StringBuilder 13 | 14 | trait RouteTest { 15 | 16 | protected class RouteFile(rawText: String, markers: List[Char] = List('@')) { 17 | private val text = rawText.stripMargin.trim 18 | 19 | private val (cleanedText: String, allMarkedPositions: Map[Char, List[Int]]) = extractPositions(rawText) 20 | 21 | val document: IDocument = { 22 | val doc = new Document(cleanedText) 23 | val partitioner = new RouteDocumentPartitioner 24 | partitioner.connect(doc) 25 | doc.setDocumentPartitioner(partitioner) 26 | doc 27 | } 28 | 29 | /** Return the only marked position by a marker char. 30 | */ 31 | def caretOffset(marker: Char): Int = { 32 | val positions = allMarkedPositions(marker) 33 | assertEquals("too many marked positions", 1, positions.size) 34 | positions(0) 35 | } 36 | 37 | /** Return the region marked by one or two marker. 38 | */ 39 | def selectedRegion(marker: Char = '@'): IRegion = { 40 | allMarkedPositions(marker) match { 41 | case a :: Nil => 42 | new Region(a, 0) 43 | case a :: b :: Nil => 44 | new Region(a, b - a) 45 | case _ => 46 | fail("Should be 1 or 2 marked position, was: " + allMarkedPositions) 47 | null 48 | } 49 | } 50 | 51 | /** Return the regions marked by pairs of markers 52 | */ 53 | def selectedRegions(marker: Char): Seq[IRegion] = { 54 | @tailrec 55 | def selectedRegions(positions: List[Int], acc: Vector[IRegion]): Vector[IRegion] = { 56 | positions match { 57 | case Nil => 58 | acc 59 | case a :: b :: tail => 60 | selectedRegions(tail, acc :+ new Region(a, b - a)) 61 | case _ => 62 | fail(s"Could not find matching pairs of $marker markers") 63 | null 64 | } 65 | } 66 | 67 | selectedRegions(allMarkedPositions(marker), Vector()) 68 | } 69 | 70 | /** Remove the markers from the raw text, and return a Map with the positions of the 71 | * markers by type. 72 | */ 73 | private def extractPositions(rawText: String): (String, Map[Char, List[Int]]) = { 74 | def addToMap(map: Map[Char, List[Int]], marker: Char, position: Int): Map[Char, List[Int]] = { 75 | val l = map(marker) :+ position 76 | map + ((marker, l)) 77 | } 78 | 79 | @tailrec 80 | def extractPositions(chars: List[Char], currentIndex: Int, cleaned: StringBuilder, positions: Map[Char, List[Int]]): (String, Map[Char, List[Int]]) = { 81 | chars match { 82 | case Nil => 83 | (cleaned.mkString, positions) 84 | case c :: tail if markers.contains(c)=> 85 | extractPositions(tail, currentIndex, cleaned, addToMap(positions, c, currentIndex)) 86 | case c :: tail => 87 | extractPositions(tail, currentIndex + 1, cleaned.append(c), positions) 88 | } 89 | } 90 | 91 | extractPositions(rawText.toList, 0, new StringBuilder(), markers.map(c => (c, Nil)).toMap) 92 | } 93 | } 94 | 95 | protected object RouteFile { 96 | def apply(text: String, markers: List[Char] = List('@')): RouteFile = new RouteFile(text, markers) 97 | } 98 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/RouteUriTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.junit.Test 4 | import org.junit.Assert._ 5 | 6 | class RouteUriTest { 7 | 8 | @Test 9 | def parsingSimple { 10 | val route = RouteUri("/ab/cd/ef") 11 | assertEquals("Wrong uri parsing", List("ab", "cd", "ef"), route.parts) 12 | assertEquals("Wrong validity [should be true/valid]", true, route.isValid) 13 | } 14 | 15 | @Test 16 | def parsingInvalid { 17 | val route = RouteUri("ab/cd/ef") 18 | assertEquals("Wrong uri parsing", List("ab", "cd", "ef"), route.parts) 19 | assertEquals("Wrong validity [should be false/invalid]", false, route.isValid) 20 | } 21 | 22 | @Test 23 | def prefixLengthNoPrefix { 24 | testPrefixLength("/ab", List(), 1) 25 | } 26 | 27 | @Test 28 | def prefixLengthNoMatch { 29 | testPrefixLength("/ab", List("ba"), -1) 30 | } 31 | 32 | @Test 33 | def prefixLengthWholeMatch { 34 | testPrefixLength("/ab/cd", List("ab", "cd"), 6) 35 | } 36 | 37 | @Test 38 | def prefixLengthPrefixMatch { 39 | testPrefixLength("/ab/cd", List("ab"), 4) 40 | } 41 | 42 | @Test 43 | def prefixLengthInvalidUri { 44 | testPrefixLength("ab/cd", List("ab"), 3) 45 | } 46 | 47 | @Test 48 | def prefixLengthEmptyUri { 49 | testPrefixLength("/", List(), 1) 50 | } 51 | 52 | @Test 53 | def prefixLengthEmptyInvalidUri { 54 | testPrefixLength("", List(), 0) 55 | } 56 | 57 | private def testPrefixLength(rawUri: String, prefixParts: List[String], expectedLength: Int) { 58 | val route = RouteUri(rawUri) 59 | assertEquals("Wrong prefix length", expectedLength, route.prefixLength(prefixParts)) 60 | } 61 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/completion/CompletionComputerTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion 2 | 3 | import org.eclipse.jface.text.Document 4 | import org.eclipse.jface.text.IDocument 5 | import org.eclipse.jface.text.ITextViewer 6 | import org.eclipse.jface.text.contentassist.ICompletionProposal 7 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor 8 | import org.junit.Assert 9 | import org.mockito.Mockito.mock 10 | import org.mockito.Mockito.when 11 | import org.scalaide.play2.routeeditor.lexical.RouteDocumentPartitioner 12 | import org.eclipse.jface.text.IDocument 13 | import org.scalaide.play2.routeeditor.RouteTest 14 | 15 | trait CompletionComputerTest extends RouteTest { 16 | 17 | /** The expected completion proposal.*/ 18 | trait ExpectedProposal 19 | 20 | /** Allows to convert the `ICompletionProposal` returned by the completion computer under test into 21 | * an `ExpectedProposal`, so that the returned completion can be compared against the test expectation. 22 | * 23 | * Subclasses will usually implement this as an '''implicit object''' so that it gets automatically 24 | * passed to `RouteFile.expectedCompletions`. 25 | */ 26 | trait AsExpectedProposal[T <: ExpectedProposal] extends (ICompletionProposal => ExpectedProposal) 27 | 28 | protected def createCompletionComputer: IContentAssistProcessor 29 | 30 | protected val TestMarker: Char = '@' 31 | 32 | protected class RouteCompletionFile(rawText: String) extends RouteFile(rawText, List(TestMarker)) { 33 | private lazy val computeCompletionProposals: Array[ICompletionProposal] = { 34 | val contentAssist = createCompletionComputer 35 | val viewer = mock(classOf[ITextViewer]) 36 | when(viewer.getDocument()).thenReturn(document) 37 | contentAssist.computeCompletionProposals(viewer, caretOffset) 38 | } 39 | 40 | def caretOffset: Int = caretOffset(TestMarker) 41 | 42 | def expectedCompletions[T <: ExpectedProposal](oracle: T*)(implicit converter: AsExpectedProposal[T]): Unit = { 43 | val completions = computeCompletionProposals.map(converter) 44 | Assert.assertEquals("Expected completions don't match.", oracle.toList, completions.toList) 45 | } 46 | 47 | } 48 | protected object RouteCompletionFile { 49 | def apply(text: String): RouteCompletionFile = new RouteCompletionFile(text.stripMargin) 50 | } 51 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/completion/HttpMethodCompletionComputerTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion 2 | 3 | import org.eclipse.jface.text.contentassist.ICompletionProposal 4 | 5 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor 6 | import org.junit.Test 7 | import org.scalaide.play2.routeeditor.lexical.HTTPKeywords 8 | 9 | class HttpMethodCompletionComputerTest extends CompletionComputerTest { 10 | 11 | case class Proposal(httpMethod: String) extends ExpectedProposal 12 | 13 | implicit object Converter extends AsExpectedProposal[Proposal] { 14 | def apply(proposal: ICompletionProposal) = Proposal(proposal.getDisplayString) 15 | } 16 | 17 | override def createCompletionComputer: IContentAssistProcessor = new HttpMethodCompletionComputer 18 | 19 | private val AllHttpMethodsProposals = HTTPKeywords.Methods map Proposal 20 | 21 | @Test 22 | def HttpGET_completion() { 23 | val route = RouteCompletionFile { "G@" } 24 | 25 | route expectedCompletions Proposal("GET") 26 | } 27 | 28 | @Test 29 | def HttpGET_completion_is_case_insensitive() { 30 | val route = RouteCompletionFile { "g@" } 31 | 32 | route expectedCompletions Proposal("GET") 33 | } 34 | 35 | @Test 36 | def HTTP_PUT_POST_completion() { 37 | val route = RouteCompletionFile { "P@" } 38 | 39 | route expectedCompletions (Proposal("PATCH"), Proposal("POST"), Proposal("PUT")) 40 | } 41 | 42 | @Test 43 | def HTTP_HEAD_completion() { 44 | val route = RouteCompletionFile { "HeA@" } 45 | 46 | route expectedCompletions Proposal("HEAD") 47 | } 48 | 49 | @Test 50 | def HTTP_DELETE_completion() { 51 | val route = RouteCompletionFile { "de@" } 52 | 53 | route expectedCompletions Proposal("DELETE") 54 | } 55 | 56 | @Test 57 | def show_all_HTTP_methods_when_word_doesnt_match() { 58 | val route = RouteCompletionFile { "DET@" } 59 | 60 | route expectedCompletions (AllHttpMethodsProposals: _*) 61 | } 62 | 63 | @Test 64 | def all_Http_Method_completion_at_beginning_of_empty_line() { 65 | val route = RouteCompletionFile { "@" } 66 | 67 | route expectedCompletions (AllHttpMethodsProposals: _*) 68 | } 69 | 70 | @Test 71 | def all_Http_Method_completetion_at_beginning_of_empty_preceded_by_empty_line() { 72 | val route = RouteCompletionFile { "\n@" } 73 | route expectedCompletions (AllHttpMethodsProposals: _*) 74 | } 75 | 76 | @Test 77 | def all_Http_Method_completion_at_end_of_empty_line() { 78 | val route = RouteCompletionFile { 79 | // whitespaces before the '*' are relevant for this test! 80 | " @" 81 | } 82 | 83 | route expectedCompletions (AllHttpMethodsProposals: _*) 84 | } 85 | 86 | @Test 87 | def all_Http_Method_completion_in_middle_of_empty_line() { 88 | val route = RouteCompletionFile { 89 | // whitespaces after the '*' are relevant for this test! 90 | " @ " 91 | } 92 | 93 | route expectedCompletions (AllHttpMethodsProposals: _*) 94 | } 95 | 96 | @Test 97 | def all_Http_Method_completion_when_cursor_is_on_already_valid_Http_method() { 98 | val route = RouteCompletionFile { "G@ET" } 99 | 100 | route expectedCompletions (AllHttpMethodsProposals: _*) 101 | } 102 | 103 | @Test 104 | def GET_Http_Method_completion_returned() { 105 | val route = RouteCompletionFile { 106 | // whitespaces after the '*' is relevant for this test! 107 | "G@ " 108 | } 109 | 110 | route expectedCompletions Proposal("GET") 111 | } 112 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/hyperlink/MethodFinderTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.hyperlink 2 | 3 | import org.junit.Test 4 | import org.junit.Assert._ 5 | import org.scalaide.core.testsetup.TestProjectSetup 6 | import org.eclipse.jdt.core.IJavaElement 7 | import org.eclipse.jdt.core.IMethod 8 | import org.eclipse.jdt.core.Signature 9 | import org.junit.Test 10 | import scala.Array.apply 11 | import scala.Array.canBuildFrom 12 | import org.junit.AfterClass 13 | import org.scalaide.core.testsetup.SDTTestUtils 14 | 15 | object MethodFinderTest extends TestProjectSetup("aProject", bundleName = "org.scala-ide.play2.tests") { 16 | @AfterClass 17 | def projectCleanUp() { 18 | SDTTestUtils.deleteProjects(project) 19 | } 20 | } 21 | 22 | class MethodFinderTest { 23 | MethodFinderTest 24 | 25 | val finder = new MethodFinder(MethodFinderTest.project.javaProject) 26 | import finder._ 27 | 28 | @Test 29 | def getParametersStringTest() = { 30 | def t = testForGetParametersString _ 31 | t ("(A)", Array("A")) 32 | t ("(A,B)", Array("A", "B")) 33 | t ("(A,B,C)", Array("A", "B", "C")) 34 | t ("()", Array()) 35 | } 36 | 37 | private def testForGetParametersString(expected: String, parameterTypes: Array[String]) = { 38 | val actual = getParametersString(parameterTypes) 39 | assertEquals("getParametersString() is not correct", expected, actual) 40 | } 41 | 42 | @Test 43 | def methodSearchTest() = { 44 | def t = testForMethodSearch _ 45 | t ("JavaClass.method1", Array()) 46 | t ("JavaClass.method2", Array()) 47 | t ("JavaClass.method2", Array("String")) 48 | t ("JavaClass.method2", Array("int")) 49 | t ("JavaClass.method2", Array("int", "String")) 50 | t ("JavaClass.method2", Array("Integer")) 51 | } 52 | 53 | private def testForMethodSearch(methodName: String, parameterTypes: Array[String]) = { 54 | val actual = dec(searchMethod(methodName, parameterTypes)) 55 | // as IMethod.getParameterTypes returns signature of types, we have to get signature for types! 56 | val expected = methodName + getParametersString(parameterTypes map (Signature.createTypeSignature(_, false))) 57 | assertEquals("Could not find method", expected, actual) 58 | } 59 | 60 | private def dec(methods: Array[IJavaElement]): String = { 61 | if (methods.length != 1) 62 | return "" 63 | val method = methods(0).asInstanceOf[IMethod] 64 | val className = method.getParent.getElementName 65 | val methodName = method.getElementName 66 | val parameterTypes = method.getParameterTypes // It returns signature of parameter types! 67 | val paramsString = getParametersString(parameterTypes) 68 | className + "." + methodName + paramsString 69 | } 70 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/lexical/AbstractRouteScannerTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.rules.IToken 4 | import org.eclipse.jface.text.rules.Token 5 | import org.junit.Assert.assertEquals 6 | import org.scalaide.play2.PlayPlugin 7 | 8 | abstract class AbstractRouteScannerTest { 9 | protected val prefStore = PlayPlugin.preferenceStore 10 | protected val scanner : AbstractRouteScanner 11 | protected val defaultToken = scanner.getDefaultReturnToken 12 | protected val wsToken = Token.WHITESPACE 13 | protected val eofToken = Token.EOF 14 | 15 | protected def check(expected: IToken) = { 16 | assertEquals(expected, scanner.nextToken()) 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/lexical/RouteActionScannerTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.Document 4 | import org.eclipse.jface.text.rules.Token 5 | import org.junit.Test 6 | 7 | class RouteActionScannerTest extends AbstractRouteScannerTest { 8 | override val scanner = new RouteActionScanner(prefStore) 9 | 10 | val packageToken = scanner.asInstanceOf[RouteActionScanner].packageToken 11 | val classToken = scanner.asInstanceOf[RouteActionScanner].classToken 12 | val methodToken = scanner.asInstanceOf[RouteActionScanner].methodToken 13 | 14 | @Test 15 | def methodTest1() = { 16 | val content = "show()" 17 | val document = new Document(content) 18 | scanner.setRange(document, 0, content.length) 19 | 20 | check(methodToken) 21 | check(defaultToken) 22 | check(Token.EOF) 23 | } 24 | @Test 25 | def methodTest2() = { 26 | val content = "show(a: Int)" 27 | val document = new Document(content) 28 | scanner.setRange(document, 0, content.length) 29 | 30 | check(methodToken) 31 | check(defaultToken) 32 | check(Token.EOF) 33 | } 34 | @Test 35 | def methodTest3() = { 36 | val content = "show(a ?= \"\")" 37 | val document = new Document(content) 38 | scanner.setRange(document, 0, content.length) 39 | 40 | check(methodToken) 41 | check(defaultToken) 42 | check(Token.EOF) 43 | } 44 | @Test 45 | def classMethodTest1() = { 46 | val content = "A.show(a ?= \"\")" 47 | val document = new Document(content) 48 | scanner.setRange(document, 0, content.length) 49 | 50 | check(classToken) 51 | check(defaultToken) 52 | check(methodToken) 53 | check(defaultToken) 54 | check(Token.EOF) 55 | } 56 | 57 | @Test 58 | def classMethodTest2() = { 59 | val content = "A.B.C.D_1.show(a ?= \"\")" 60 | val document = new Document(content) 61 | scanner.setRange(document, 0, content.length) 62 | 63 | check(classToken) 64 | check(defaultToken) 65 | check(classToken) 66 | check(defaultToken) 67 | check(classToken) 68 | check(defaultToken) 69 | check(classToken) 70 | check(defaultToken) 71 | check(methodToken) 72 | check(defaultToken) 73 | check(Token.EOF) 74 | } 75 | 76 | @Test 77 | def packageClassMethodTest1() = { 78 | val content = "test.Class.show()" 79 | val document = new Document(content) 80 | scanner.setRange(document, 0, content.length) 81 | 82 | check(packageToken) 83 | check(classToken) 84 | check(defaultToken) 85 | check(methodToken) 86 | check(defaultToken) 87 | check(Token.EOF) 88 | } 89 | @Test 90 | def packageClassMethodTest2() = { 91 | val content = "test.test1.Class.show()" 92 | val document = new Document(content) 93 | scanner.setRange(document, 0, content.length) 94 | 95 | check(packageToken) 96 | check(classToken) 97 | check(defaultToken) 98 | check(methodToken) 99 | check(defaultToken) 100 | check(Token.EOF) 101 | } 102 | @Test 103 | def packageClassMethodTest3() = { 104 | val content = "test.test1.t_2.t__3.tAt.Class.show()" 105 | val document = new Document(content) 106 | scanner.setRange(document, 0, content.length) 107 | 108 | check(packageToken) 109 | check(classToken) 110 | check(defaultToken) 111 | check(methodToken) 112 | check(defaultToken) 113 | check(Token.EOF) 114 | } 115 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/routeeditor/lexical/RouteURIScannerTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.Document 4 | import org.junit.Test 5 | 6 | class RouteURIScannerTest extends AbstractRouteScannerTest { 7 | override val scanner = new RouteURIScanner(prefStore) 8 | 9 | private val dynamicToken = scanner.asInstanceOf[RouteURIScanner].dynamic 10 | 11 | @Test 12 | def dynamicTest1() = { 13 | val content = "/hello/route/*id" 14 | val document = new Document(content) 15 | scanner.setRange(document, 0, content.length) 16 | 17 | check(defaultToken) 18 | check(dynamicToken) 19 | check(eofToken) 20 | } 21 | 22 | @Test 23 | def dynamicTest2() = { 24 | val content = "/hello/:id" 25 | val document = new Document(content) 26 | scanner.setRange(document, 0, content.length) 27 | 28 | check(defaultToken) 29 | check(dynamicToken) 30 | check(eofToken) 31 | } 32 | 33 | @Test 34 | def dynamicTest3() = { 35 | val content = "/hello/route_1/$id_2" 36 | val document = new Document(content) 37 | scanner.setRange(document, 0, content.length) 38 | 39 | check(defaultToken) 40 | check(dynamicToken) 41 | check(eofToken) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/templateeditor/BeforeAfterTemplateVersion.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor 2 | 3 | import org.junit.After 4 | import org.junit.Before 5 | import org.scalaide.play2.templateeditor.processing.TemplateVersionExhibitor 6 | 7 | trait BeforeAfterTemplateVersion { 8 | @Before def setUp(): Unit = { 9 | TemplateVersionExhibitor.set(Some("2.6")) 10 | } 11 | 12 | @After def tearDown(): Unit = { 13 | TemplateVersionExhibitor.clean() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/templateeditor/lexical/TemplatePartitionTokniserTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import scala.annotation.tailrec 4 | 5 | import org.eclipse.jdt.internal.core.util.SimpleDocument 6 | import org.eclipse.jface.text.TypedRegion 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Assert.assertTrue 9 | import org.junit.Test 10 | import org.scalaide.play2.templateeditor.BeforeAfterTemplateVersion 11 | import org.scalaide.util.eclipse.RegionUtils 12 | 13 | class TemplatePartitionTokeniserTest extends BeforeAfterTemplateVersion { 14 | 15 | def s(offset: Int, length: Int) = new TypedRegion(offset, length, TemplatePartitions.TEMPLATE_SCALA) 16 | def d(offset: Int, length: Int) = new TypedRegion(offset, length, TemplatePartitions.TEMPLATE_DEFAULT) 17 | def c(offset: Int, length: Int) = new TypedRegion(offset, length, TemplatePartitions.TEMPLATE_COMMENT) 18 | def tg(offset: Int, length: Int) = new TypedRegion(offset, length, TemplatePartitions.TEMPLATE_TAG) 19 | def p(offset: Int, length: Int) = new TypedRegion(offset, length, TemplatePartitions.TEMPLATE_PLAIN) 20 | 21 | @Test 22 | def definitionSection() { 23 | val p1 = "@(param: String)" 24 | testForTokenise(List(d(0, 1), s(1, p1.length() - 1)), p1) 25 | } 26 | 27 | @Test 28 | def simpleTokeniseTest() = { 29 | def t = testForTokenise _ 30 | val p2 = "@*comment*@" 31 | t(List(c(0, p2.length())), p2) 32 | val p3 = "" 33 | t(List(tg(0, 10), tg(10, 11)), p3) 34 | val p4 = "Some plain text" 35 | t(List(p(0, p4.length())), p4) 36 | val p5 = "@methodCall(arg)" 37 | t(List(d(0, 1), s(1, p5.length() - 1)), p5) 38 | val p6 = """@{val blockOfScalaCode = ""}""" 39 | t(List(d(0, 1), s(1, p6.length() - 1)), p6) 40 | } 41 | 42 | 43 | 44 | @Test 45 | def complexTokeniseTest() = { 46 | def t = testForTokenise _ 47 | // bug #20 48 | // reusable block 49 | val p1 = """@test = { 50 | is viewed 51 | }""" 52 | t(List(d(0, 1), s(1, 4), d(5, 4), p(9, 3), p(12, 10), d(22, 1)), p1) 53 | // bug #20 54 | // reusable block with scala code 55 | val p2 = """@test = @{ 56 | val x = "x string" 57 | }""" 58 | t(List(d(0, 1), s(1, 4), d(5, 4), s(9, 22)), p2) 59 | // bug #18 60 | // for statements without yield 61 | val p3 = """@for()""" 62 | t(List(d(0, 1), s(1, 5)), p3) 63 | } 64 | 65 | private def testForTokenise(expected: List[TypedRegion], program: String) = { 66 | val tokeniser = new TemplatePartitionTokeniser 67 | val actual = tokeniser.tokenise(new SimpleDocument(program)) 68 | 69 | @tailrec 70 | def noOverlap(list: List[TypedRegion]): Boolean = { 71 | list match { 72 | case head :: second :: tail => 73 | import org.scalaide.util.eclipse.RegionUtils.RichRegion 74 | !head.intersects(second) && noOverlap(list.tail) 75 | case _ => 76 | true 77 | } 78 | } 79 | 80 | def complete: Boolean = { 81 | def testComplete(start: Int, list: List[TypedRegion]): Boolean = { 82 | list match { 83 | case hd :: tail => if (start == hd.getOffset()) testComplete(hd.getOffset() + hd.getLength(), tail) else false 84 | case _ => start == program.length() 85 | } 86 | } 87 | testComplete(0, actual) 88 | } 89 | 90 | assertTrue("list has overlap", noOverlap(actual)) 91 | assertTrue("list is not complete", complete) 92 | assertEquals("list doesn't match", expected, actual) 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/src/org/scalaide/play2/templateeditor/sse/TemplateContentDescriberTest.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse 2 | 3 | import org.junit.Test 4 | import org.junit.Assert._ 5 | import org.eclipse.core.runtime.content.IContentDescriber 6 | import java.io.ByteArrayInputStream 7 | 8 | class TemplateContentDescriberTest { 9 | 10 | import IContentDescriber._ 11 | 12 | @Test 13 | def emptyFile() { 14 | test("Empty file", "", INDETERMINATE) 15 | } 16 | 17 | @Test 18 | def notTemplate() { 19 | test("Not template", "", INVALID) 20 | } 21 | 22 | @Test 23 | def notTemplateWithEmptyLines() { 24 | test("Not template with emtyp lines", """ 25 | 26 | 27 | 28 | """, INVALID) 29 | } 30 | 31 | @Test 32 | def notTemplateWithLeadingSpaces() { 33 | test("Not template with leading spaces", " ", INVALID) 34 | } 35 | 36 | @Test 37 | def startWithComment() { 38 | test("Start with comment", "@********@", VALID) 39 | } 40 | 41 | @Test 42 | def startWithParameters() { 43 | test("Start with parameters", "@(abc: Int)(test: String)", VALID) 44 | } 45 | 46 | @Test 47 | def startWithCommentWithEmptyLines() { 48 | test("Start with comment with emtyp lines", """ 49 | 50 | 51 | @********@ 52 | """, VALID) 53 | } 54 | 55 | @Test 56 | def startWithParametersWithEmptyLines() { 57 | test("Start with parameters with emtyp lines", """ 58 | 59 | 60 | @(abc: Int)(test: String) 61 | """, VALID) 62 | } 63 | 64 | @Test 65 | def startWithCommentWithLeadingSpaces() { 66 | test("Start with comment with leading spaces", " @********@", VALID) 67 | } 68 | 69 | @Test 70 | def startWithParametersWithLeadingSpaces() { 71 | test("Start with parameters with leading spaces", " @(abc: Int)(test: String)", VALID) 72 | } 73 | 74 | private def test(description: String, content: String, expectedValue: Int) { 75 | val describer = new TemplateContentDescriber() 76 | 77 | assertEquals("Wrong value for " + description, expectedValue, describer.describe(new ByteArrayInputStream(content.getBytes("UTF-8")), null)) 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | aProject 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.scala-ide.sdt.core.scalanature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/app/views/index.scala.html: -------------------------------------------------------------------------------- 1 | @(message: String) 2 | 3 | @message -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/app/views/scala_compiler_error.scala.html: -------------------------------------------------------------------------------- 1 | @(message: String) 2 | 3 | @main("Welcome") { 4 |

@foo

5 | } 6 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/app/views/template_parse_error.scala.html: -------------------------------------------------------------------------------- 1 | @(message: String) 2 | 3 | @main("Welcome") { 4 |

@

5 | } 6 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/app/views/template_unclosed_comment.scala.html: -------------------------------------------------------------------------------- 1 | @* 2 | 3 | @(message: String) 4 | 5 | @main("Welcome") { 6 |

@

7 | } 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/moreviews/more.scala.html: -------------------------------------------------------------------------------- 1 | @(message: String) 2 | 3 | @message -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/route: -------------------------------------------------------------------------------- 1 | GET /clients/:id controllers.Clients.show(id: Long) 2 | # Display a client. 3 | GET /clients/:id controllers.Clients.show(id: Long) 4 | GET /clients controllers.Clients.list() 5 | GET /clients/:id controllers.Clients.show(id: Long) 6 | GET /files/*name controllers.Application.download(name) 7 | GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long) 8 | GET / controllers.Application.homePage() 9 | # Extract the page parameter from the path. 10 | # i.e. http://myserver.com/index 11 | GET /:page controllers.Application.show(page) 12 | # Extract the page parameter from the query string. 13 | # i.e. http://myserver.com/?page=index 14 | GET / controllers.Application.show(page) 15 | GET /client/:id controllers.Clients.show(id: Long) 16 | # Extract the page parameter from the path, or fix the value for / 17 | GET / controllers.Application.show(page = "home") 18 | GET /:page controllers.Application.show(page) 19 | # Pagination links, like /clients?page=3 20 | GET /clients controllers.Clients.list(page: Integer ?= 1) 21 | # Hello action 22 | GET /hello/:name controllers.Application.hello(name) 23 | 24 | # Amir's tests 25 | GET /hello/:str controllers.Test.test_underline() #comment at here! 26 | test.test.test2.A.show() 27 | Integer.parseInt(a: String) 28 | #kdjfa /dkfjsa -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/src/org/example/JavaClass.java: -------------------------------------------------------------------------------- 1 | 2 | public class JavaClass { 3 | public void method1(){ 4 | 5 | } 6 | 7 | public void method2(){ 8 | 9 | } 10 | 11 | public void method2(int a){ 12 | 13 | } 14 | 15 | public void method2(String s){ 16 | 17 | } 18 | 19 | public void method2(Integer i){ 20 | 21 | } 22 | 23 | public void method2(int a, String s){ 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/aProject/src/org/example/ScalaClass.scala: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | class ScalaClass { 4 | 5 | } 6 | 7 | object ScalaClass { 8 | 9 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | resolver 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.scala-ide.sdt.core.scalanature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/app/controllers/Application.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import play.api.mvc.{Controller, Action} 4 | 5 | object Application { 6 | 7 | def/*!*/ index = Action { 8 | } 9 | 10 | def/*!*/ post(id: Long) = Action { 11 | } 12 | 13 | def/*!*/ postText(text: String, id: Int) = Action { 14 | } 15 | 16 | def internalPostText1(text: String, /*!*/id: Char) = Action { 17 | } 18 | 19 | def internalPostText2(text: String, id: Short) = Action { 20 | /*!*/ 21 | } 22 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/app/controllers/JavaApplication.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import play.mvc.Controller; 4 | import play.mvc.Result; 5 | import java.io.File; 6 | 7 | public class JavaApplication extends Controller { 8 | 9 | public static Result index() { 10 | /*!*/ 11 | return null; 12 | } 13 | 14 | public static Result index2(long lng) { 15 | /*!*/ 16 | return null; 17 | } 18 | 19 | public static Result index3(String str, int id) { 20 | /*!*/ 21 | return null; 22 | } 23 | 24 | public static Result index4(File f, int id) { 25 | /*!*/ 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/app/controllers/JavaNonController.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import play.mvc.Controller; 4 | import play.mvc.Result; 5 | 6 | public class JavaNonController extends Controller { 7 | 8 | // not static 9 | public Result index() { 10 | /*!*/ 11 | return null; 12 | } 13 | 14 | // not returning resultResult 15 | public static String index2(long lng) { 16 | /*!*/ 17 | return null; 18 | } 19 | 20 | // not public 21 | static Result index3(String str, int id) { 22 | /*!*/ 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/app/controllers/NonController.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import play.api.mvc.{Controller, Action} 4 | 5 | trait Action 6 | 7 | object NonController { 8 | 9 | def/*!*/ index = new Action 10 | 11 | def/*!*/ post(id: Long) = "dummy" 12 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/src/play/api/mvc/Action.scala: -------------------------------------------------------------------------------- 1 | package play.api.mvc 2 | 3 | class Action extends EssentialAction 4 | 5 | object Action { 6 | def apply[A](f: => A) = new Action 7 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/src/play/api/mvc/EssentialAction.scala: -------------------------------------------------------------------------------- 1 | package play.api.mvc 2 | 3 | class EssentialAction 4 | 5 | object EssentialAction { 6 | def apply[A](f: => A) = new EssentialAction 7 | } 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/src/play/mvc/Controller.java: -------------------------------------------------------------------------------- 1 | package play.mvc; 2 | 3 | public abstract class Controller {} 4 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/resolver/src/play/mvc/Result.java: -------------------------------------------------------------------------------- 1 | package play.mvc; 2 | 3 | abstract class Result {} 4 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | routeActionCompletions 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.scala-ide.sdt.core.scalanature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/RootScalaApplication.scala: -------------------------------------------------------------------------------- 1 | import play.mvc._ 2 | 3 | class RootScalaApplication { 4 | def simple: AnyRef = ??? 5 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/RootStaticJavaApplication.java: -------------------------------------------------------------------------------- 1 | import play.*; 2 | import play.mvc.*; 3 | 4 | public class RootStaticJavaApplication extends Controller { 5 | public static Result simple() { 6 | return new Result() {}; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/ScalaPackage/package.scala: -------------------------------------------------------------------------------- 1 | package object ScalaPackage { 2 | def simple: AnyRef = ??? 3 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/java/AbstractApplication.java: -------------------------------------------------------------------------------- 1 | package controllers.java; 2 | 3 | import play.*; 4 | import play.mvc.*; 5 | 6 | public abstract class AbstractApplication extends Controller { 7 | public static Result hello(String name) { 8 | return new Result {}; 9 | } 10 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/java/Application.java: -------------------------------------------------------------------------------- 1 | package controllers.java; 2 | 3 | import play.*; 4 | import play.mvc.*; 5 | 6 | public class Application extends Controller { 7 | 8 | public static Result hello(String name) { 9 | return new Result {}; 10 | } 11 | 12 | public static Result withIntegerArg(Integer i) { 13 | return new Result {}; 14 | } 15 | 16 | public static void nonActionMethod(String name) {} 17 | 18 | public Result nonStaticMethod(String name) { 19 | return new Result {}; 20 | } 21 | 22 | public static Result fieldIsNotValidAction = new Result {}; 23 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/java/InterfaceApplication.java: -------------------------------------------------------------------------------- 1 | package controllers.java; 2 | 3 | 4 | public interface InterfaceApplication { 5 | 6 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/java/SubApplication.java: -------------------------------------------------------------------------------- 1 | package controllers.java; 2 | 3 | import play.*; 4 | import play.mvc.*; 5 | 6 | public class SubApplication extends Application { 7 | 8 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/AbstractApp.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | abstract class AbstractApp { 7 | def actionMethod() = Action {} 8 | 9 | val actionVal = Action {} 10 | 11 | def nonActionMethod(): Unit = () 12 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/ActionWithMangledName.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | object ActionWithMangledName { 7 | def ++==++() = Action {} 8 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/AppClass.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | class AppClass { 7 | def actionMethod() = Action {} 8 | 9 | val actionVal = Action {} 10 | 11 | def nonActionMethod(): Unit = () 12 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/AppNotExtendingController.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | object AppNotExtendingController { 7 | def actionMethod() = Action {} 8 | 9 | def nonActionMethod(): Unit = () 10 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/MembersVisibility.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | object MembersVisibility { 7 | private def actionMethod1() = Action {} 8 | private[scala] def actionMethod2() = Action {} 9 | protected def actionMethod3() = Action {} 10 | protected[scala] def actionMethod4() = Action {} 11 | 12 | private val actionVal1 = Action {} 13 | private[scala] val actionVal2 = Action {} 14 | protected val actionVal3 = Action {} 15 | protected[scala] val actionVal4 = Action {} 16 | 17 | def visibleMethod = Action {} 18 | 19 | /** The completion engine in the route file should NOT report abstract methods.*/ 20 | def abstractMethod: Action 21 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/SubAppClass.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | object SubAppClass extends AppClass -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/TraitApp.scala: -------------------------------------------------------------------------------- 1 | package controllers.scala 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | trait TraitApp { 7 | def actionMethod() = Action {} 8 | 9 | def nonActionMethod(): Unit = () 10 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/empty/Empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/scala/empty/Empty -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/app/controllers/simple/SimpleScalaPlayApp.scala: -------------------------------------------------------------------------------- 1 | package controllers.simple 2 | 3 | import play.api._ 4 | import play.api.mvc._ 5 | 6 | object SimpleScalaPlayApp extends Controller { 7 | def foo = Action {} 8 | 9 | def bar() = Action {} 10 | 11 | val buz = Action {} 12 | 13 | lazy val lazyBuz = Action {} 14 | 15 | var boo = Action {} 16 | 17 | def nonActionMethod: Unit = () 18 | 19 | def withStringArg(s: String) = Action {} 20 | 21 | def withIntArg(i: Int) = Action {} 22 | 23 | def overloadedAction(s: String) = Action {} 24 | def overloadedAction(id: Long) = Action {} 25 | def overloadedAction() = Action {} 26 | 27 | def overloadedEssentialAction(s: String) = EssentialAction {} 28 | def overloadedEssentialAction(id: Long) = EssentialAction {} 29 | def overloadedEssentialAction() = EssentialAction {} 30 | } 31 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/src/play/api/mvc/Action.scala: -------------------------------------------------------------------------------- 1 | package play.api.mvc 2 | 3 | trait Action extends EssentialAction 4 | 5 | object Action { 6 | def apply[A](f: => A) = new Action {} 7 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/src/play/api/mvc/EssentialAction.scala: -------------------------------------------------------------------------------- 1 | package play.api.mvc 2 | 3 | trait EssentialAction 4 | 5 | object EssentialAction { 6 | def apply[A](f: => A) = new EssentialAction {} 7 | } 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/src/play/mvc/Controller.java: -------------------------------------------------------------------------------- 1 | package play.mvc; 2 | 3 | public abstract class Controller {} 4 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeActionCompletions/src/play/mvc/Result.java: -------------------------------------------------------------------------------- 1 | package play.mvc; 2 | 3 | abstract public class Result {} 4 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeHyperlink/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeHyperlink/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | routeHyperlink 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.scala-ide.sdt.core.scalanature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeHyperlink/app/controllers/JavaApplication.java: -------------------------------------------------------------------------------- 1 | package controllers; 2 | 3 | import model.Element; 4 | 5 | public class JavaApplication { 6 | 7 | public static Object intro() { 8 | throw new UnsupportedOperationException(); 9 | } 10 | 11 | public static Object withEmptyParams() { 12 | throw new UnsupportedOperationException(); 13 | } 14 | 15 | public static Object pInt(int a) { 16 | throw new UnsupportedOperationException(); 17 | } 18 | 19 | public static Object pString(String a) { 20 | throw new UnsupportedOperationException(); 21 | } 22 | 23 | public static Object pRef(Element a) { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | public static Object overloaded(int b) { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | public static Object overloaded(String c) { 32 | throw new UnsupportedOperationException(); 33 | } 34 | 35 | public static Object overloaded(Element b) { 36 | throw new UnsupportedOperationException(); 37 | } 38 | 39 | public static Object overloaded(String s, Element b) { 40 | throw new UnsupportedOperationException(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeHyperlink/app/controllers/ScalaApplication.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import model.Element 4 | 5 | object ScalaApplication { 6 | 7 | def intro: AnyRef = ??? 8 | 9 | def withEmptyParams(): AnyRef = ??? 10 | 11 | def pInt(a: Int): AnyRef = ??? 12 | 13 | def pString(a: String): AnyRef = ??? 14 | 15 | def pRef(a: Element): AnyRef = ??? 16 | 17 | def overloaded(b: Int): AnyRef = ??? 18 | 19 | def overloaded(c: String): AnyRef = ??? 20 | 21 | def overloaded(b: Element): AnyRef = ??? 22 | 23 | def overloaded(s: String, b: Element): AnyRef = ??? 24 | } 25 | 26 | class ScalaClass { 27 | 28 | def intro: AnyRef = ??? 29 | 30 | def withEmptyParams(): AnyRef = ??? 31 | 32 | def pInt(a: Int): AnyRef = ??? 33 | 34 | def pString(a: String): AnyRef = ??? 35 | 36 | def pRef(a: Element): AnyRef = ??? 37 | 38 | def overloaded(b: Int): AnyRef = ??? 39 | 40 | def overloaded(c: String): AnyRef = ??? 41 | 42 | def overloaded(b: Element): AnyRef = ??? 43 | 44 | def overloaded(s: String, b: Element): AnyRef = ??? 45 | } -------------------------------------------------------------------------------- /org.scala-ide.play2.tests/test-workspace/routeHyperlink/app/model/Element.scala: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | case class Element(id: Int) -------------------------------------------------------------------------------- /org.scala-ide.play2.update-site/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2.update-site 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.pde.UpdateSiteBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.pde.UpdateSiteNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /org.scala-ide.play2.update-site/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.scala-ide 7 | org.scala-ide.play2.build 8 | 0.11.0-SNAPSHOT 9 | 10 | org.scala-ide.play2.update-site 11 | eclipse-update-site 12 | 13 | -------------------------------------------------------------------------------- /org.scala-ide.play2.update-site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --> 11 | 12 | -------------------------------------------------------------------------------- /org.scala-ide.play2/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /org.scala-ide.play2/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.scala-ide.play2 4 | 5 | 6 | 7 | 8 | 9 | org.scala-ide.sdt.core.scalabuilder 10 | 11 | 12 | 13 | org.eclipse.pde.ManifestBuilder 14 | 15 | 16 | 17 | org.eclipse.pde.SchemaBuilder 18 | 19 | 20 | 21 | 22 | org.eclipse.pde.PluginNature 23 | org.scala-ide.sdt.core.scalanature 24 | org.eclipse.jdt.core.javanature 25 | 26 | 27 | -------------------------------------------------------------------------------- /org.scala-ide.play2/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Play 2 Support for Scala IDE 4 | Bundle-SymbolicName: org.scala-ide.play2;singleton:=true 5 | Bundle-Version: 0.11.0.qualifier 6 | Bundle-Vendor: scala-ide.org 7 | Bundle-ActivationPolicy: lazy 8 | Bundle-Localization: plugin 9 | Require-Bundle: 10 | org.eclipse.core.runtime, 11 | org.eclipse.debug.ui, 12 | org.eclipse.help, 13 | org.eclipse.jdt.core, 14 | org.eclipse.jdt.debug.ui, 15 | org.eclipse.jdt.junit, 16 | org.eclipse.jdt.launching, 17 | org.eclipse.jdt.ui, 18 | org.eclipse.jface.text, 19 | org.eclipse.ui, 20 | org.eclipse.ui.console, 21 | org.eclipse.ui.editors, 22 | org.eclipse.ui.forms, 23 | org.eclipse.ui.ide, 24 | org.scala-lang.scala-library;bundle-version="[2.12,2.13)", 25 | org.scala-lang.scala-compiler;bundle-version="[2.12,2.13)", 26 | org.scala-lang.scala-reflect;bundle-version="[2.12,2.13)", 27 | org.scala-ide.sdt.core;bundle-version="[4.0.0,5.0.0)", 28 | org.eclipse.core.resources, 29 | scalariform, 30 | org.eclipse.core.filesystem, 31 | org.eclipse.wst.sse.ui, 32 | org.eclipse.wst.sse.core, 33 | org.eclipse.wst.html.ui, 34 | org.eclipse.wst.html.core, 35 | org.eclipse.wst.xml.core, 36 | org.eclipse.emf.common, 37 | org.eclipse.wst.xml.ui, 38 | org.eclipse.wst.css.core, 39 | org.eclipse.wst.validation, 40 | org.eclipse.wst.jsdt.web.ui, 41 | org.eclipse.wst.jsdt.web.core, 42 | org.eclipse.wst.jsdt.core, 43 | org.scala-lang.modules.scala-xml, 44 | org.scala-lang.modules.scala-parser-combinators 45 | Import-Package: 46 | com.ibm.icu.text;apply-aspects:=false;org.eclipse.swt.graphics;apply-aspects:=false, 47 | scala.tools.eclipse.contribution.weaving.jdt.ui.javaeditor.formatter;apply-aspects:=false, 48 | scala.xml, 49 | scala.util.parsing.input 50 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 51 | Bundle-Activator: org.scalaide.play2.PlayPlugin 52 | Export-Package: org.scalaide.play2,org.scalaide.play2.lexical,org.scal 53 | aide.play2.properties,org.scalaide.play2.quickassist,org.scalaide.pla 54 | y2.routeeditor,org.scalaide.play2.routeeditor.completion,org.scalaide 55 | .play2.routeeditor.completion.action,org.scalaide.play2.routeeditor.f 56 | ormatter,org.scalaide.play2.routeeditor.handlers,org.scalaide.play2.r 57 | outeeditor.hyperlink,org.scalaide.play2.routeeditor.lexical,org.scala 58 | ide.play2.routeeditor.properties,org.scalaide.play2.templateeditor,or 59 | g.scalaide.play2.templateeditor.compiler,org.scalaide.play2.templatee 60 | ditor.completion,org.scalaide.play2.templateeditor.hyperlink,org.scal 61 | aide.play2.templateeditor.lexical,org.scalaide.play2.templateeditor.p 62 | roperties,org.scalaide.play2.templateeditor.reconciler,org.scalaide.p 63 | lay2.templateeditor.sse,org.scalaide.play2.templateeditor.sse.hyperli 64 | nk,org.scalaide.play2.templateeditor.sse.lexical,org.scalaide.play2.t 65 | emplateeditor.sse.model,org.scalaide.play2.templateeditor.sse.style,o 66 | rg.scalaide.play2.templateeditor.sse.validation,org.scalaide.play2.ut 67 | il,org.scalaide.play2.wizards,org.scalaide.play2.templateeditor.proce 68 | ssing 69 | -------------------------------------------------------------------------------- /org.scala-ide.play2/about.ini: -------------------------------------------------------------------------------- 1 | # Property "featureImage" contains path to feature image (32x32) 2 | featureImage=about.png 3 | aboutText=Play 2 Support for Scala IDE\n\ 4 | (c) Typesafe\n\ 5 | \n\ 6 | Play 2 Support for Scala IDE provides editor for route file and template files.\n\ 7 | Visit https://github.com/scala-ide/scala-ide-play2/wiki/Documentation\n\n\ 8 | Typesafe Team: Amir Shaikhha, Luc Bourlier, Mirco Dotta, and Iulian Dragos.\n\ 9 | -------------------------------------------------------------------------------- /org.scala-ide.play2/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/about.png -------------------------------------------------------------------------------- /org.scala-ide.play2/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = target/classes/ 3 | bin.includes = META-INF/,\ 4 | .,\ 5 | plugin.xml,\ 6 | plugin.properties,\ 7 | icons/,\ 8 | about.ini,\ 9 | about.png,\ 10 | -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/newtemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/newtemplate.png -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/pin.png -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/play.png -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/routes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/routes.png -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/sample.gif -------------------------------------------------------------------------------- /org.scala-ide.play2/icons/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/icons/web.png -------------------------------------------------------------------------------- /org.scala-ide.play2/plugin.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scala-ide/scala-ide-play2/d9c116f2c5e1e83b1093628395bc11e8dab377ac/org.scala-ide.play2/plugin.properties -------------------------------------------------------------------------------- /org.scala-ide.play2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.scala-ide 7 | org.scala-ide.play2.build 8 | 0.11.0-SNAPSHOT 9 | 10 | org.scala-ide.play2 11 | eclipse-plugin 12 | 13 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/IssueTracker.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | object IssueTracker { 4 | final val Url: String = "https://github.com/scala-ide/scala-ide-play2/issues" 5 | 6 | def createATicketMessage: String = s"This is a bug. Please, file a ticket at ${Url}." 7 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/PlayClassNames.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | trait PlayClassNames { 4 | protected def controllerClassFullName: String 5 | protected def actionClassFullName: String 6 | } 7 | 8 | object ScalaPlayClassNames { 9 | final val ControllerClassFullName = "play.api.mvc.Controller" 10 | final val ActionClassFullName = "play.api.mvc.EssentialAction" 11 | } 12 | 13 | trait ScalaPlayClassNames extends PlayClassNames { 14 | override protected def controllerClassFullName: String = ScalaPlayClassNames.ControllerClassFullName 15 | override protected def actionClassFullName: String = ScalaPlayClassNames.ActionClassFullName 16 | } 17 | 18 | object JavaPlayClassNames { 19 | final val ControllerClassFullName = "play.mvc.Controller" 20 | final val ActionClassFullName = "play.mvc.Result" 21 | } 22 | 23 | trait JavaPlayClassNames extends PlayClassNames { 24 | override protected def controllerClassFullName: String = JavaPlayClassNames.ControllerClassFullName 25 | override protected def actionClassFullName: String = JavaPlayClassNames.ActionClassFullName 26 | 27 | private final def unresolvedActionClassName: String = "QResult;" 28 | private final def resolvedBinaryFullActionClassName: String = "Lplay/mvc/Result;" 29 | 30 | final protected def allActionClassNameCandidates: Set[String] = Set(unresolvedActionClassName, resolvedBinaryFullActionClassName) 31 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/PlayPlugin.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | import org.scalaide.core.IScalaPlugin 4 | import org.eclipse.core.resources.IProject 5 | import org.eclipse.core.resources.ResourcesPlugin 6 | import org.eclipse.core.runtime.Status 7 | import org.eclipse.jface.preference.IPreferenceStore 8 | import org.eclipse.jface.resource.ImageDescriptor 9 | import org.eclipse.ui.plugin.AbstractUIPlugin 10 | import org.osgi.framework.BundleContext 11 | import org.eclipse.jface.resource.ImageRegistry 12 | import org.scalaide.play2.util.Images 13 | 14 | object PlayPlugin { 15 | @volatile 16 | private var plugin: PlayPlugin = _ 17 | 18 | final val PluginId = "org.scala-ide.play2" 19 | final val RouteFormatterMarginId = PluginId + ".routeeditor.margin" 20 | final val RouteFormatterFormatOnSaveId = PluginId + ".routeeditor.formatonsave" 21 | final val TemplateExtension = "scala.html" 22 | 23 | /** Return the current plugin instace */ 24 | def instance(): PlayPlugin = plugin 25 | 26 | /** Return the plugin-wide preference store */ 27 | def preferenceStore: IPreferenceStore = plugin.getPreferenceStore 28 | 29 | def getImageDescriptor(path: String): ImageDescriptor = { 30 | AbstractUIPlugin.imageDescriptorFromPlugin(PluginId, path); 31 | } 32 | 33 | def log(status: Int, msg: String, ex: Throwable = null): Unit = { 34 | plugin.getLog.log(new Status(status, plugin.getBundle().getSymbolicName(), msg, ex)) 35 | } 36 | } 37 | 38 | class PlayPlugin extends AbstractUIPlugin { 39 | override def start(context: BundleContext): Unit = { 40 | super.start(context) 41 | PlayPlugin.plugin = this 42 | initializeProjects() 43 | } 44 | 45 | override def stop(context: BundleContext): Unit = { 46 | PlayPlugin.plugin = null 47 | super.stop(context) 48 | } 49 | 50 | def asPlayProject(project: IProject): Option[PlayProject] = { 51 | val scalaProject = IScalaPlugin().asScalaProject(project) 52 | scalaProject map (PlayProject(_)) 53 | } 54 | 55 | private def initializeProjects(): Unit = { 56 | for { 57 | iProject <- ResourcesPlugin.getWorkspace.getRoot.getProjects 58 | if iProject.isOpen 59 | playProject <- asPlayProject(iProject) 60 | } playProject.initialize() 61 | } 62 | 63 | override def initializeImageRegistry(reg: ImageRegistry) { 64 | reg.put(Images.ROUTES_ICON, Images.ROUTES_ICON_DESCRIPTOR) 65 | reg.put(Images.HTTP_METHODS_ICON, Images.HTTP_METHODS_ICON_DESCRIPTOR) 66 | reg.put(Images.URL_ICON, Images.URL_ICON_DESCRIPTOR) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/PlayProject.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2 2 | 3 | import scala.collection.mutable 4 | 5 | import org.eclipse.core.resources.IFile 6 | import org.eclipse.core.resources.ProjectScope 7 | import org.eclipse.jface.preference.IPreferenceStore 8 | import org.eclipse.ui.preferences.ScopedPreferenceStore 9 | import org.scalaide.core.IScalaProject 10 | import org.scalaide.play2.properties.PlayPreferences 11 | import org.scalaide.play2.templateeditor.TemplateCompilationUnit 12 | import org.scalaide.play2.util.SyncedScopedPreferenceStore 13 | 14 | class PlayProject private (val scalaProject: IScalaProject) { 15 | val cachedPreferenceStore = new SyncedScopedPreferenceStore(scalaProject.underlying, PlayPlugin.PluginId) 16 | 17 | /** 18 | * Return additional imports that are automatically added to template files. 19 | * 20 | * @return The additional imports, or the empty string if none defined. 21 | */ 22 | def templateImports(extension: String): String = { 23 | import org.scalaide.play2.properties.PlayPreferences._ 24 | (defaultImports + cachedPreferenceStore.getString(TemplateImports)).replace("%format%", extension) 25 | } 26 | 27 | /** Return a new project-scoped preference store for this project. */ 28 | def generateScopedPreferenceStore: IPreferenceStore = new ScopedPreferenceStore(new ProjectScope(scalaProject.underlying), PlayPlugin.PluginId) 29 | 30 | /** 31 | * Tries to load the scala template files 32 | */ 33 | def initialize() { 34 | val templateCompilationUnits = for ( 35 | r <- scalaProject.underlying.members() if r.isInstanceOf[IFile] && r.getFullPath().toString().endsWith("." + PlayPlugin.TemplateExtension) 36 | ) yield TemplateCompilationUnit(r.asInstanceOf[IFile], false) 37 | templateCompilationUnits foreach (_.initialReconcile()) 38 | // TODO: Why was there a second round of ask reload here? 39 | // templateCompilationUnits.reverse foreach (_.askReload()) 40 | } 41 | 42 | /** 43 | * FIXME: This method should probably not exist. 44 | * Template files can be anywhere 45 | * 46 | * @return the absolute location of the project directory 47 | */ 48 | lazy val sourceDir = scalaProject.underlying.getLocation().toFile() 49 | } 50 | 51 | object PlayProject { 52 | private val projects = (new mutable.HashMap) withDefault { (scalaProject: IScalaProject) => new PlayProject(scalaProject) } 53 | def apply(scalaProject: IScalaProject): PlayProject = { 54 | projects(scalaProject) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/lexical/PlayPartitionTokeniser.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.lexical 2 | 3 | import org.eclipse.jface.text.TypedRegion 4 | import org.eclipse.jface.text.IDocument 5 | /** 6 | * Interface for tokeniser 7 | */ 8 | trait PlayPartitionTokeniser { 9 | def tokenise(document: IDocument): List[TypedRegion] 10 | } 11 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/properties/PlayPreferences.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.properties 2 | 3 | import org.eclipse.swt.SWT 4 | import org.eclipse.swt.widgets.Composite 5 | import org.eclipse.swt.widgets.Control 6 | import org.eclipse.ui.IWorkbench 7 | import org.eclipse.ui.IWorkbenchPreferencePage 8 | import org.eclipse.ui.dialogs.PropertyPage 9 | 10 | object PlayPreferences { 11 | 12 | /** 13 | * Preference containing the list of import to automatically add to the generate template code. 14 | * The data is stored as the string which will be added to the generated source (to not recreate 15 | * it everytime). The empty String represent an empty import list. 16 | * [[org.scalaide.play2.properties.PlayPreferences.serializeImports]] and [[org.scalaide.play2.properties.PlayPreferences.deserializeImports]] 17 | * need to be used when converting the preference value to/from Array[String]. 18 | */ 19 | final val TemplateImports = "templateImports" 20 | 21 | final val DefaultTemplateImports = List( 22 | "models._", 23 | "controllers._", 24 | "play.api.i18n._", 25 | "play.api.mvc._", 26 | "play.api.data._", 27 | "views.%format%._", 28 | "play.api.templates.PlayMagic._", 29 | "play.mvc.Http.Context.Implicit._") 30 | 31 | final val defaultImports = serializeImports(DefaultTemplateImports.toArray) 32 | 33 | final val PlayVersion = "playVersion" 34 | 35 | final val PlaySupportedVersion = List("2.6", "2.5") 36 | 37 | final val DefaultPlayVersion = PlaySupportedVersion.head 38 | 39 | // Regex used for the operations on the templateImports preference. 40 | private val importsRegex = "import ([^\n]+)\n".r 41 | 42 | /** 43 | * @see [[org.scalaide.play2.properties.PlayPreferences.TemplateImports]] 44 | */ 45 | def serializeImports(entries: Array[String]): String = { 46 | if (entries.length == 0) { 47 | "" 48 | } else { 49 | entries.mkString("import ", "\nimport ", "\n") 50 | } 51 | } 52 | 53 | /** 54 | * @see [[org.scalaide.play2.properties.PlayPreferences.TemplateImports]] 55 | */ 56 | def deserializeImports(s: String): Array[String] = { 57 | if (s.length == 0) { 58 | new Array(0) 59 | } else { 60 | importsRegex.findAllIn(s).matchData.map(m => m.group(1)).toArray 61 | } 62 | } 63 | 64 | } 65 | 66 | /** An empty preference page, used as an intermediary node under the Play page. */ 67 | class PlayPreferences extends PropertyPage with IWorkbenchPreferencePage { 68 | override def createContents(parent: Composite): Control = { 69 | new Composite(parent, SWT.NULL) 70 | } 71 | 72 | override def init(workbench: IWorkbench): Unit = {} 73 | } 74 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/properties/PreferenceInitializer.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.properties 2 | 3 | import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer 4 | import org.scalaide.play2.PlayPlugin 5 | 6 | class PreferenceInitializer extends AbstractPreferenceInitializer { 7 | import PlayPreferences._ 8 | 9 | override def initializeDefaultPreferences(): Unit = { 10 | PlayPlugin.preferenceStore.setDefault(PlayVersion, DefaultPlayVersion) 11 | PlayPlugin.preferenceStore.setDefault(TemplateImports, "") 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/properties/ProjectPropertyPage.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.properties 2 | 3 | import org.eclipse.core.resources.IProject 4 | import org.eclipse.core.runtime.IAdaptable 5 | import org.eclipse.jdt.core.IJavaProject 6 | import org.eclipse.jface.dialogs.IInputValidator 7 | import org.eclipse.jface.dialogs.InputDialog 8 | import org.eclipse.jface.preference.FieldEditorPreferencePage 9 | import org.eclipse.jface.preference.IPreferenceStore 10 | import org.eclipse.jface.preference.ListEditor 11 | import org.eclipse.jface.window.Window 12 | import org.eclipse.swt.widgets.Composite 13 | import org.eclipse.swt.widgets.Display 14 | import org.eclipse.ui.IWorkbenchPropertyPage 15 | import org.scalaide.play2.PlayPlugin 16 | 17 | /** 18 | * Preference page displayed in the property dialog of (play) projects. 19 | * Used from the UI thread. 20 | */ 21 | class ProjectPropertyPage extends FieldEditorPreferencePage(FieldEditorPreferencePage.GRID) with IWorkbenchPropertyPage { 22 | 23 | /** 24 | * Preference field to display the list of extra imports. 25 | */ 26 | private class ImportsFieldEditor(name: String, labelText: String, parent: Composite) extends ListEditor(name, labelText, parent) { 27 | 28 | override protected def createList(entries: Array[String]): String = 29 | PlayPreferences.serializeImports(entries) 30 | 31 | override protected def parseString(s: String): Array[String] = 32 | PlayPreferences.deserializeImports(s) 33 | 34 | override protected def getNewInputObject(): String = { 35 | 36 | val dlg = new InputDialog( 37 | Display.getCurrent().getActiveShell(), 38 | "Play template import", 39 | "Enter an import value:", 40 | "com.example._", 41 | new IInputValidator { 42 | def isValid(text: String) = null 43 | }); 44 | 45 | if (dlg.open() == Window.OK) { 46 | dlg.getValue() 47 | } else { 48 | null 49 | } 50 | } 51 | 52 | } 53 | 54 | // The preference store being edited. 55 | // The data require to get the store is provided by the workbench during the page lifecycle. 56 | private var prefStore: IPreferenceStore = _ 57 | 58 | // Members declared in org.eclipse.jface.preference.FieldEditorPreferencePage 59 | 60 | override def createFieldEditors() { 61 | addField(new ProjectPropertyPage.PlayProjectVersion(getFieldEditorParent())) 62 | addField(new ImportsFieldEditor(PlayPreferences.TemplateImports, "Template default imports", getFieldEditorParent())) 63 | } 64 | 65 | // Members declared in org.eclipse.ui.IWorkbenchPropertyPage 66 | 67 | // doesn't seem to be a real function for this method. 68 | // It looks like it leaked from the implementation of PropertyPage. 69 | override def getElement(): IAdaptable = null 70 | 71 | override def setElement(element: IAdaptable) { 72 | prefStore = element match { 73 | case project: IProject => 74 | PlayPlugin.instance().asPlayProject(project).get.generateScopedPreferenceStore 75 | case project: IJavaProject => 76 | PlayPlugin.instance().asPlayProject(project.getProject()).get.generateScopedPreferenceStore 77 | } 78 | } 79 | 80 | override def doGetPreferenceStore(): IPreferenceStore = 81 | prefStore 82 | } 83 | 84 | object ProjectPropertyPage { 85 | import org.eclipse.jface.preference.ComboFieldEditor 86 | import org.scalaide.play2.properties.PlayPreferences._ 87 | 88 | private def supportedVersions = PlaySupportedVersion.map(version => Array(version, version)).toArray 89 | 90 | class PlayProjectVersion(parent: Composite) extends ComboFieldEditor(PlayVersion, "Play version", supportedVersions, parent) 91 | } 92 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/quickassist/AddRouteEntryProposal.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.quickassist 2 | 3 | import org.eclipse.jface.text.IDocument 4 | 5 | import org.eclipse.swt.graphics.Image 6 | import org.scalaide.core.internal.statistics.Features.Feature 7 | import org.scalaide.core.internal.statistics.Groups.Editing 8 | import org.scalaide.core.quickassist.BasicCompletionProposal 9 | 10 | object AddRouteEntry extends Feature("AddRouteEntry")("Add entry to route file", Editing) 11 | 12 | case class AddRouteEntryProposal(display: String, image: Image = null)(f: IDocument => Unit) extends BasicCompletionProposal(AddRouteEntry, 100, display, image) { 13 | override def applyProposal(doc: IDocument) = f(doc) 14 | } 15 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/quickassist/ControllerMethod.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.quickassist 2 | 3 | /** A controller method definition, with helper methods to generate the route-file 4 | * syntax. 5 | */ 6 | case class ControllerMethod(typeName: String, methodName: String, params: List[(String, String)]) { 7 | import ControllerMethod._ 8 | 9 | def fullName: String = 10 | "%s.%s".format(typeName, methodName) 11 | 12 | /** Return the route-call syntax, simplifying types if possible. 13 | * 14 | * A parameter of type String is omitted, and primitive types are stripped the 15 | * `scala` package prefix. 16 | * 17 | * @see http://www.playframework.com/documentation/2.1.1/ScalaRouting 18 | */ 19 | def toRouteCallSyntax: String = { 20 | val parts = for ((name, tpe) <- params) yield simplifyType(tpe) match { 21 | case None => name 22 | case Some(simpleTpe) => s"$name: $simpleTpe" 23 | } 24 | 25 | s"$fullName(${parts.mkString(", ")})" 26 | } 27 | } 28 | 29 | object ControllerMethod { 30 | /** Map a type to a pretty name to use in the route file. 31 | * Strings are mapped to the empty string 32 | */ 33 | private val simplifyType = Map( 34 | "java.lang.String" -> None, 35 | "scala.String" -> None, 36 | "String" -> None, 37 | "scala.Boolean" -> Some("Boolean"), 38 | "scala.Byte" -> Some("Byte"), 39 | "scala.Short" -> Some("Short"), 40 | "scala.Char" -> Some("Char"), 41 | "scala.Int" -> Some("Int"), 42 | "scala.Long" -> Some("Long"), 43 | "scala.Float" -> Some("Float"), 44 | "scala.Double" -> Some("Double"), 45 | 46 | // Java types 47 | "boolean" -> Some("Boolean"), 48 | "byte" -> Some("Byte"), 49 | "short" -> Some("Short"), 50 | "char" -> Some("Char"), 51 | "int" -> Some("Int"), 52 | "long" -> Some("Long"), 53 | "float" -> Some("Float"), 54 | "double" -> Some("Double")) withDefault (Some.apply) 55 | 56 | private val FullNameRegex = """(.+)\.([^.]+)""".r 57 | 58 | /** Create a new instance by extracting the type and the method name. 59 | */ 60 | def apply(fullName: String, params: List[(String, String)]): ControllerMethod = 61 | fullName match { 62 | case FullNameRegex(typeName, methodName) => 63 | new ControllerMethod(typeName, methodName, params) 64 | case _ => 65 | throw new IllegalArgumentException(s"'$fullName' cannot be parsed as a full method name") 66 | } 67 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/EditorMessages.properties: -------------------------------------------------------------------------------- 1 | Editor.Format.label=&Format 2 | Editor.Format.tooltip=Format the Selected Text 3 | Editor.Format.description=Format the Selected Text -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/EditorMessages.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import java.util.ResourceBundle 4 | 5 | /** 6 | * Manage the NLSed data. Needed for the editor actions. 7 | */ 8 | object EditorMessages { 9 | lazy val resourceBundle= ResourceBundle.getBundle("org.scalaide.play2.routeeditor.EditorMessages") 10 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/HasScalaProject.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.scalaide.core.IScalaProject 4 | 5 | /** @note This marker trait should be moved in the scala-ide sdt.core bundle. */ 6 | trait HasScalaProject { 7 | def getScalaProject: Option[IScalaProject] 8 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteAction.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 5 | import org.eclipse.jface.text.IRegion 6 | import org.scalaide.play2.quickassist.ControllerMethod 7 | 8 | object RouteAction { 9 | 10 | /** Regex for the an action with parameters. 11 | * "package.Object.action(...xxx...)" 12 | * or 13 | * "@package.Class.action(...xxx...)" 14 | */ 15 | private final val ActionWithParametersRegex = """@?([^\(]*)\.([^\.\(]*)\(([^\)]*)\)""".r 16 | 17 | /** Regex for the an action without parameters. 18 | * "package.Object.action" 19 | * or 20 | * "@package.Class.action" 21 | */ 22 | private final val ActionWithoutParametersRegex = """@?([^\(]*)\.([^\.\(]*)""".r 23 | 24 | /** Regex for the individual parameters. 25 | * The support format is: "page: Int ?= 1" 26 | */ 27 | private final val ParameterWithTypeRegex = """(.*):([^\?]*)(\?=.*)?""".r 28 | 29 | private final val ParameterWithoutTypeRegex = """([^\?]*)(\?=.*)?""".r 30 | 31 | /** Return the route action description at the location, using the document 32 | * partitions. 33 | */ 34 | def routeActionAt(document: IDocument, offset: Int): Option[RouteAction] = { 35 | val partition = document.getPartition(offset) 36 | if (RoutePartitions.isRouteAction(partition.getType())) { 37 | document.get(partition.getOffset(), partition.getLength()) match { 38 | case ActionWithoutParametersRegex(typeName, methodName) => 39 | Some(new RouteAction(typeName, methodName, Nil, partition)) 40 | case ActionWithParametersRegex(typeName, methodName, parameters) => 41 | Some(new RouteAction(typeName, methodName, parseParameterTypes(parameters), partition)) 42 | case s => 43 | None 44 | } 45 | } else { 46 | None 47 | } 48 | } 49 | 50 | private def parseParameterTypes(parameters: String): List[(String, String)] = { 51 | if (parameters.isEmpty()) { 52 | Nil 53 | } else { 54 | parameters.split(",").toList.map { 55 | case ParameterWithTypeRegex(name, tpe, _) => 56 | (name.trim, tpe.trim) 57 | case ParameterWithoutTypeRegex(name, _) => 58 | // if the type is not specified, the default is String 59 | (name.trim, "String") 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | /** Description of an action in a route file. 67 | */ 68 | class RouteAction(typeName: String, methodName: String, params: List[(String, String)], val region: IRegion) extends ControllerMethod(typeName, methodName, params) -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteConfiguration.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.eclipse.jface.text.IDocument 5 | import org.eclipse.jface.text.contentassist.ContentAssistant 6 | import org.eclipse.jface.text.contentassist.IContentAssistant 7 | import org.eclipse.jface.text.formatter.MultiPassContentFormatter 8 | import org.eclipse.jface.text.hyperlink.IHyperlinkDetector 9 | import org.eclipse.jface.text.presentation.IPresentationReconciler 10 | import org.eclipse.jface.text.source.ISourceViewer 11 | import org.eclipse.jface.text.source.SourceViewerConfiguration 12 | import org.eclipse.jface.util.PropertyChangeEvent 13 | import org.scalaide.play2.routeeditor.completion.ActionContentAssistProcessor 14 | import org.scalaide.play2.routeeditor.completion.HttpMethodCompletionComputer 15 | import org.scalaide.play2.routeeditor.completion.UriCompletionComputer 16 | import org.scalaide.play2.routeeditor.formatter.RouteFormattingStrategy 17 | import org.scalaide.play2.routeeditor.hyperlink.RouteHyperlinkDetector 18 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 19 | import org.eclipse.jface.util.IPropertyChangeListener 20 | 21 | class RouteConfiguration(prefStore: IPreferenceStore, routeEditor: RouteEditor) extends SourceViewerConfiguration with IPropertyChangeListener { 22 | private val reconciler: RoutePresentationReconciler = new RoutePresentationReconciler(prefStore) 23 | 24 | override def getDoubleClickStrategy(sourceViewer: ISourceViewer, contentType: String) = { 25 | new RouteDoubleClickStrategy() 26 | } 27 | 28 | override def getConfiguredContentTypes(sourceViewer: ISourceViewer) = { 29 | RoutePartitions.getTypes 30 | } 31 | 32 | override def getContentAssistant(sourceViewer: ISourceViewer): IContentAssistant = { 33 | val assistant = new ContentAssistant 34 | assistant.setAutoActivationDelay(50) 35 | assistant.enableAutoActivation(true) 36 | assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)) 37 | assistant.setContentAssistProcessor(new HttpMethodCompletionComputer, RoutePartitions.ROUTE_HTTP) 38 | assistant.setContentAssistProcessor(new UriCompletionComputer, RoutePartitions.ROUTE_URI) 39 | assistant.setContentAssistProcessor(new ActionContentAssistProcessor(routeEditor), RoutePartitions.ROUTE_ACTION) 40 | assistant 41 | } 42 | 43 | override def getHyperlinkDetectors(sourceViewer: ISourceViewer): Array[IHyperlinkDetector] = Array(new RouteHyperlinkDetector(routeEditor)) 44 | 45 | override def getPresentationReconciler(sourceViewer: ISourceViewer): IPresentationReconciler = reconciler 46 | 47 | override def getContentFormatter(viewer: ISourceViewer) = { 48 | val formatter = new MultiPassContentFormatter(getConfiguredDocumentPartitioning(viewer), IDocument.DEFAULT_CONTENT_TYPE) 49 | formatter.setMasterStrategy(new RouteFormattingStrategy(routeEditor)) 50 | formatter 51 | } 52 | 53 | override def propertyChange(event: PropertyChangeEvent): Unit = { 54 | reconciler.propertyChange(event) 55 | } 56 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteDocumentProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.eclipse.ui.editors.text.FileDocumentProvider 5 | import org.scalaide.play2.routeeditor.lexical.RouteDocumentPartitioner 6 | 7 | class RouteDocumentProvider extends FileDocumentProvider { 8 | override protected def createDocument(element: Object): IDocument = { 9 | val document = super.createDocument(element); 10 | if (document != null) { 11 | val partitioner = new RouteDocumentPartitioner() 12 | partitioner.connect(document) 13 | document.setDocumentPartitioner(partitioner) 14 | } 15 | document 16 | } 17 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteDoubleClickStrategy.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.eclipse.jface.text.DefaultTextDoubleClickStrategy 4 | 5 | class RouteDoubleClickStrategy extends DefaultTextDoubleClickStrategy -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RoutePresentationReconciler.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.eclipse.jface.text.presentation.PresentationReconciler 5 | import org.eclipse.jface.text.rules.DefaultDamagerRepairer 6 | import org.eclipse.jface.text.rules.ITokenScanner 7 | import org.eclipse.jface.util.PropertyChangeEvent 8 | import org.scalaide.play2.routeeditor.lexical.RouteActionScanner 9 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 10 | import org.scalaide.play2.routeeditor.lexical.RouteURIScanner 11 | import org.eclipse.jface.util.IPropertyChangeListener 12 | import org.scalaide.core.lexical.ScalaCodeScanners 13 | 14 | class RoutePresentationReconciler(prefStore: IPreferenceStore) extends PresentationReconciler with IPropertyChangeListener { 15 | 16 | private val scanner = 17 | ScalaCodeScanners.singleTokenScanner(prefStore, RouteSyntaxClasses.DEFAULT) 18 | 19 | private val httpScanner = 20 | ScalaCodeScanners.singleTokenScanner(prefStore, RouteSyntaxClasses.HTTP_KEYWORD) 21 | 22 | private val uriScanner = 23 | new RouteURIScanner(prefStore) 24 | 25 | private val actionScanner = 26 | new RouteActionScanner(prefStore) 27 | 28 | private val commentScanner = 29 | ScalaCodeScanners.singleTokenScanner(prefStore, RouteSyntaxClasses.COMMENT) 30 | 31 | handlePartition(scanner, RoutePartitions.ROUTE_DEFAULT) 32 | handlePartition(httpScanner, RoutePartitions.ROUTE_HTTP) 33 | handlePartition(uriScanner, RoutePartitions.ROUTE_URI) 34 | handlePartition(actionScanner, RoutePartitions.ROUTE_ACTION) 35 | handlePartition(commentScanner, RoutePartitions.ROUTE_COMMENT) 36 | 37 | private def handlePartition(scan: ITokenScanner, token: String) = { 38 | val dr = new DefaultDamagerRepairer(scan); 39 | setDamager(dr, token) 40 | setRepairer(dr, token) 41 | } 42 | 43 | override def propertyChange(event: PropertyChangeEvent) { 44 | scanner.adaptToPreferenceChange(event) 45 | httpScanner.adaptToPreferenceChange(event) 46 | uriScanner.adaptToPreferenceChange(event) 47 | actionScanner.adaptToPreferenceChange(event) 48 | commentScanner.adaptToPreferenceChange(event) 49 | } 50 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/RouteSyntaxClasses.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor 2 | 3 | import org.scalaide.ui.syntax.ScalaSyntaxClass 4 | import org.scalaide.ui.syntax.ScalaSyntaxClass.Category 5 | 6 | object RouteSyntaxClasses { 7 | val DEFAULT = ScalaSyntaxClass("Default", "route.default") 8 | val COMMENT = ScalaSyntaxClass("Comment", "route.comment") 9 | val URI = ScalaSyntaxClass("URI", "route.uri") 10 | val URI_DYNAMIC = ScalaSyntaxClass("URI Dynamic", "route.uriDynamic") 11 | val ACTION = ScalaSyntaxClass("Action", "route.action") 12 | val ACTION_PACKAGE = ScalaSyntaxClass("Action package", "route.actionPackage") 13 | val ACTION_CLASS = ScalaSyntaxClass("Action class", "route.actionClass") 14 | val ACTION_METHOD = ScalaSyntaxClass("Action method name", "route.actionMethod") 15 | val HTTP_KEYWORD = ScalaSyntaxClass("HTTP keyword", "route.httpKeyword") 16 | 17 | val routeURICategory = Category("URI", List( 18 | URI, URI_DYNAMIC)) 19 | 20 | val routeActionCategory = Category("Action", List( 21 | ACTION, ACTION_PACKAGE, ACTION_CLASS, ACTION_METHOD)) 22 | 23 | val routeOtherCategory = Category("Other", List( 24 | DEFAULT, COMMENT, HTTP_KEYWORD)) 25 | 26 | val categories = List(routeURICategory, routeActionCategory, routeOtherCategory) 27 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/completion/ActionContentAssistProcessor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion 2 | 3 | import org.scalaide.core.IScalaProject 4 | import org.scalaide.logging.HasLogger 5 | 6 | import org.eclipse.jface.text.ITextViewer 7 | import org.eclipse.jface.text.contentassist.ICompletionProposal 8 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor 9 | import org.eclipse.jface.text.contentassist.IContextInformation 10 | import org.scalaide.play2.routeeditor.HasScalaProject 11 | import org.scalaide.play2.routeeditor.completion.action.ActionCompletionComputer 12 | 13 | class ActionContentAssistProcessor(routeEditor: HasScalaProject) extends IContentAssistProcessor with HasLogger { 14 | 15 | override def getCompletionProposalAutoActivationCharacters(): Array[Char] = Array('.') 16 | 17 | override def getContextInformationAutoActivationCharacters(): Array[Char] = null 18 | 19 | override def getErrorMessage = null 20 | 21 | override def getContextInformationValidator = null 22 | 23 | override def computeCompletionProposals(viewer: ITextViewer, offset: Int): Array[ICompletionProposal] = { 24 | val proposals = { 25 | for (project <- routeEditor.getScalaProject) 26 | yield computeCompletionProposals(project, viewer, offset) 27 | } 28 | proposals getOrElse null 29 | } 30 | 31 | private def computeCompletionProposals(project: IScalaProject, viewer: ITextViewer, offset: Int): Array[ICompletionProposal] = { 32 | val document = viewer.getDocument 33 | 34 | import org.scalaide.core.compiler.IScalaPresentationCompiler.Implicits._ 35 | val completions = project.presentationCompiler { compiler => 36 | compiler.asyncExec { 37 | val actionComputer = new ActionCompletionComputer(compiler) 38 | actionComputer.computeCompletionProposals(document, offset) 39 | }.getOrElse(Nil)() 40 | } getOrElse Nil 41 | 42 | completions.sorted.toArray 43 | } 44 | 45 | override def computeContextInformation(viewer: ITextViewer, offset: Int): Array[IContextInformation] = { 46 | null 47 | } 48 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/completion/HttpMethodsCompletionComputer.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.eclipse.jface.text.IRegion 5 | import org.eclipse.jface.text.ITextViewer 6 | import org.eclipse.jface.text.contentassist.ICompletionProposal 7 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor 8 | import org.eclipse.jface.text.contentassist.IContextInformation 9 | import org.eclipse.swt.graphics.Image 10 | import org.eclipse.swt.graphics.Point 11 | import org.scalaide.ui.editor.WordFinder 12 | import org.scalaide.play2.PlayPlugin 13 | import org.scalaide.play2.routeeditor.lexical.HTTPKeywords 14 | import org.scalaide.play2.util.Images 15 | 16 | class HttpMethodCompletionComputer extends IContentAssistProcessor { 17 | 18 | override def getCompletionProposalAutoActivationCharacters(): Array[Char] = null 19 | 20 | override def getContextInformationAutoActivationCharacters(): Array[Char] = null 21 | 22 | override def getErrorMessage = null 23 | 24 | override def getContextInformationValidator = null 25 | 26 | override def computeCompletionProposals(viewer: ITextViewer, offset: Int): Array[ICompletionProposal] = { 27 | val region = WordFinder.findWord(viewer.getDocument(), offset) 28 | val input = viewer.getDocument().get(region.getOffset(), region.getLength()).toUpperCase 29 | 30 | val filteredCompletions = HTTPKeywords.Methods.filter(_.take(region.getLength) == input) 31 | val completions = { 32 | // If the `input` matches one of the valid HTTP methods, return full list of alternatives as the 33 | // user likely wants to change the current valid input with another one. 34 | if (HTTPKeywords.Methods.contains(input) || filteredCompletions.isEmpty) HTTPKeywords.Methods 35 | else filteredCompletions 36 | } 37 | 38 | completions.map(new HttpMethodCompletionProposal(region, _)) 39 | } 40 | 41 | override def computeContextInformation(viewer: ITextViewer, offset: Int): Array[IContextInformation] = { 42 | null 43 | } 44 | 45 | private class HttpMethodCompletionProposal(region: IRegion, displayString: String) extends ICompletionProposal { 46 | override def apply(document: IDocument): Unit = { 47 | document.replace(region.getOffset, region.getLength, displayString) 48 | } 49 | 50 | override def getSelection(document: IDocument): Point = 51 | new Point(region.getOffset() + displayString.length, 0) // always put caret *after* the inserted completion 52 | override def getAdditionalProposalInfo: String = null 53 | override def getDisplayString: String = displayString 54 | override def getImage: Image = PlayPlugin.instance.getImageRegistry().get(Images.HTTP_METHODS_ICON) 55 | override def getContextInformation: IContextInformation = null 56 | } 57 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/completion/UriCompletionComputer.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.eclipse.jface.text.IRegion 5 | import org.eclipse.jface.text.ITextViewer 6 | import org.eclipse.jface.text.contentassist.ICompletionProposal 7 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor 8 | import org.eclipse.jface.text.contentassist.IContextInformation 9 | import org.eclipse.swt.graphics.Image 10 | import org.eclipse.swt.graphics.Point 11 | import org.scalaide.ui.editor.WordFinder 12 | import org.scalaide.play2.PlayPlugin 13 | import org.scalaide.play2.routeeditor.lexical.RouteDocumentPartitioner 14 | import org.scalaide.play2.util.Images 15 | import org.scalaide.play2.routeeditor.RouteUri 16 | import org.scalaide.play2.routeeditor.RouteUriWithRegion 17 | 18 | class UriCompletionComputer extends IContentAssistProcessor { 19 | 20 | override def getCompletionProposalAutoActivationCharacters(): Array[Char] = 21 | Array('/') 22 | 23 | override def getContextInformationAutoActivationCharacters(): Array[Char] = null 24 | 25 | override def getErrorMessage = null 26 | 27 | override def getContextInformationValidator = null 28 | 29 | override def computeCompletionProposals(viewer: ITextViewer, offset: Int): Array[ICompletionProposal] = { 30 | val document = viewer.getDocument() 31 | 32 | val word = WordFinder.findWord(document, offset) 33 | // only consider the prefix (word to the left of caret) 34 | val rawUri = document.get(word.getOffset, (offset - word.getOffset())) 35 | val uri = RouteUri(rawUri) 36 | 37 | val existingUris = RouteUriWithRegion.existingUrisInDocument(document).filter(_ != uri) 38 | 39 | // If the `rawUri` is empty then add '/' to the returned set of proposals 40 | val defaultUriProposal = if (rawUri.isEmpty) Set(RouteUri("/")) else Set.empty 41 | 42 | val staticUrisProposals = { 43 | if (RouteUri(rawUri).isValid) existingUris.flatMap(_.subUrisStartingWith(rawUri)) 44 | // If the `rawUri` isn't valid, then proposals will contain all possible valid permutations of existing URIs 45 | else existingUris.flatMap(_.subUrisStartingWith("")) 46 | } 47 | 48 | val dynamicUrisProposals = { 49 | // Add dynamics parts to the proposals only if completion happens on an empty URI or after a slash 50 | if (rawUri.isEmpty) RouteUri("/").dynamicUris 51 | else if (rawUri.last == '/') RouteUri(rawUri).dynamicUris 52 | else staticUrisProposals 53 | } 54 | 55 | val allUrisProposals = defaultUriProposal ++ staticUrisProposals ++ dynamicUrisProposals 56 | 57 | val sortedProposals = allUrisProposals.toList.sorted(RouteUri.AlphabeticOrder) 58 | 59 | sortedProposals.map(new UriCompletionProposal(word, _)).toArray 60 | } 61 | 62 | override def computeContextInformation(viewer: ITextViewer, offset: Int): Array[IContextInformation] = { 63 | null 64 | } 65 | 66 | private class UriCompletionProposal(region: IRegion, uri: RouteUri) extends ICompletionProposal { 67 | override def apply(document: IDocument): Unit = { 68 | document.replace(region.getOffset, region.getLength, getDisplayString) 69 | } 70 | 71 | override def getSelection(document: IDocument): Point = 72 | new Point(region.getOffset() + getDisplayString.length, 0) // always put caret *after* the inserted completion 73 | override def getAdditionalProposalInfo: String = null 74 | override def getDisplayString: String = uri.toString 75 | override def getImage: Image = PlayPlugin.instance.getImageRegistry().get(Images.URL_ICON) 76 | override def getContextInformation: IContextInformation = null 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/completion/action/ActionCompletionProposal.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion.action 2 | 3 | import org.scalaide.core.completion.MemberKind 4 | import org.scalaide.ui.completion.ScalaCompletionProposal 5 | 6 | import org.eclipse.jdt.internal.ui.JavaPluginImages 7 | import org.eclipse.jface.text.IDocument 8 | import org.eclipse.jface.text.IRegion 9 | import org.eclipse.jface.text.contentassist.ICompletionProposal 10 | import org.eclipse.jface.text.contentassist.IContextInformation 11 | import org.eclipse.swt.graphics.Image 12 | import org.eclipse.swt.graphics.Point 13 | 14 | /** Completion for action method in route file. 15 | * 16 | * @param replaceRegion The region in the document that will be replaced if this proposal is applied. 17 | * @param simpleName The name of a package, type or method. 18 | * @param kind The kind of member of this proposal, i.e., val, var, object, class, package, ... 19 | * @param isJava Is this completion for a Java member. 20 | */ 21 | case class ActionCompletionProposal(replaceRegion: IRegion, val simpleName: String, val kind: MemberKind.Value, val isJava: Boolean) 22 | extends ICompletionProposal { 23 | 24 | import ActionCompletionProposal.javaFieldImage 25 | 26 | override def apply(document: IDocument): Unit = { 27 | document.replace(replaceRegion.getOffset, replaceRegion.getLength, simpleName) 28 | } 29 | 30 | override def getSelection(document: IDocument): Point = 31 | new Point(replaceRegion.getOffset + simpleName.length, 0) // always put caret *after* the inserted completion 32 | 33 | override def getAdditionalProposalInfo: String = null 34 | override def getDisplayString: String = simpleName 35 | override def getImage: Image = kind match { 36 | case MemberKind.Def => ScalaCompletionProposal.defImage 37 | case MemberKind.Class if !isJava => ScalaCompletionProposal.classImage 38 | case MemberKind.Class if isJava => ScalaCompletionProposal.javaClassImage 39 | case MemberKind.Object => ScalaCompletionProposal.objectImage 40 | case MemberKind.Package => ScalaCompletionProposal.packageImage 41 | case MemberKind.Val => ScalaCompletionProposal.valImage 42 | case MemberKind.Var => javaFieldImage 43 | case _ => ScalaCompletionProposal.valImage 44 | } 45 | override def getContextInformation: IContextInformation = null 46 | 47 | } 48 | 49 | object ActionCompletionProposal { 50 | private val javaFieldImage = JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PUBLIC) 51 | 52 | implicit object ByKindAndAlphabetically extends Ordering[ActionCompletionProposal] { 53 | override def compare(x: ActionCompletionProposal, y: ActionCompletionProposal): Int = { 54 | /* If `kind` is a package, then only types and packages can be suggested to the user. In this case, 55 | * types should be shown before packages. The only other alternative is that `kind` is a member, 56 | * in this case sort the members alphabetically. 57 | */ 58 | val compared = relevance(y) - relevance(x) 59 | if (compared == 0) x.simpleName.compareTo(y.simpleName) else compared 60 | } 61 | 62 | private def relevance(that: ActionCompletionProposal): Int = { 63 | if (that.kind == MemberKind.Package) 10 64 | else 100 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/completion/action/ActionRouteInput.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.completion.action 2 | 3 | /** A simple wrapper for parsing action method invocation in a route file. 4 | * 5 | * An action method invocation in a route file is a fully qualified method (of return type Action - 6 | * or Result, in Java), in a Play controller class. 7 | * 8 | * @param input The (possibly incomplete) action method invocation a route file. 9 | */ 10 | private[action] class ActionRouteInput(input: String) { 11 | 12 | /** If the passed `fullName` starts with a '@', the controller class is instantiated by the framework. 13 | * 14 | * @see Section '''Managed Controller classes instantiation''' in http://www.playframework.com/documentation/2.1.1/Highlights 15 | * for more details. 16 | */ 17 | def isControllerClassInstantiation: Boolean = input.startsWith("@") 18 | 19 | /** Returns the `input` without the leading '@', if present. */ 20 | def fullName: String = { 21 | if (isControllerClassInstantiation) input.substring(1) 22 | else input 23 | } 24 | 25 | /** Returns the prefix of the action method invocation. Hence, a valid prefix is either a fully 26 | * qualified package (could also be the empty package) or a class. 27 | * 28 | * @note If present, the leading '@' is removed. 29 | */ 30 | def prefix: String = fullName.substring(0, Math.max(0, fullName.lastIndexOf('.'))) 31 | 32 | /** Returns the suffix of the action method invocation. Hence, a valid suffix is either a 33 | * package, class or method name. 34 | * 35 | * @note If present, the leading '@' is removed. 36 | */ 37 | def suffix: String = fullName.substring(fullName.lastIndexOf('.') + 1) 38 | 39 | override def toString: String = input 40 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/handlers/Format.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.handlers 2 | 3 | import org.eclipse.core.commands.AbstractHandler 4 | import org.eclipse.core.commands.ExecutionEvent 5 | import org.eclipse.jface.text.ITextOperationTarget 6 | import org.eclipse.jface.text.source.ISourceViewer 7 | import org.eclipse.ui.handlers.HandlerUtil 8 | import org.scalaide.play2.routeeditor.RouteEditor 9 | 10 | /** 11 | * Invoke the formatter on a Route editor 12 | */ 13 | class Format extends AbstractHandler { 14 | override def execute(event: ExecutionEvent): AnyRef = { 15 | HandlerUtil.getActiveEditor(event) match { 16 | case editor: RouteEditor => 17 | // in our case, the viewer is always an ITexOperationTarget 18 | editor.getViewer.asInstanceOf[ITextOperationTarget].doOperation(ISourceViewer.FORMAT) 19 | } 20 | null 21 | } 22 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/hyperlink/MethodFinder.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.hyperlink 2 | 3 | import org.eclipse.jdt.core.IJavaElement 4 | import org.eclipse.jdt.core.search.IJavaSearchConstants 5 | import org.eclipse.jdt.core.search.IJavaSearchScope 6 | import org.eclipse.jdt.core.search.SearchPattern 7 | import org.eclipse.jdt.internal.core.search.BasicSearchEngine 8 | import scala.Array.apply 9 | import org.eclipse.core.runtime.NullProgressMonitor 10 | import org.eclipse.jdt.core.IJavaProject 11 | 12 | /** 13 | * Find Java methods in a given project. 14 | */ 15 | class MethodFinder(project: IJavaProject) { 16 | /** 17 | * Returns an array of method elements which matches with the 18 | * criterion. 19 | * 20 | * @param methodName the name of method which we'd like to find 21 | * @param parameterTypes array of type of parameter of desired method 22 | * @return array of method element which matches the search 23 | */ 24 | def searchMethod(methodName: String, parameterTypes: Array[String]): Array[IJavaElement] = { 25 | val stringPattern = methodName + getParametersString(parameterTypes) 26 | val methodPattern = SearchPattern.createPattern(stringPattern, IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH) 27 | searchMethod(methodPattern) 28 | } 29 | 30 | private def searchMethod(methodPattern: SearchPattern): Array[IJavaElement] = { 31 | val requestor = doSearch(methodPattern) 32 | requestor.matchedElements.toArray 33 | } 34 | 35 | private def doSearch(pattern: SearchPattern): MethodSearchRequestor = { 36 | val participants = Array(BasicSearchEngine.getDefaultSearchParticipant) 37 | val scope = createJavaSearchScope() 38 | val requestor = new MethodSearchRequestor 39 | new BasicSearchEngine().search(pattern, participants, scope, requestor, new NullProgressMonitor) 40 | requestor 41 | } 42 | 43 | private[hyperlink] def getParametersString(parameterTypes: Array[String]) = { 44 | parameterTypes.mkString("(", ",", ")") 45 | } 46 | 47 | private def createJavaSearchScope(): IJavaSearchScope = { 48 | BasicSearchEngine.createJavaSearchScope(Array(project)) 49 | } 50 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/hyperlink/MethodSearchRequestor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.hyperlink 2 | 3 | import scala.collection.mutable 4 | import org.eclipse.jdt.core.IJavaElement 5 | import org.eclipse.jdt.core.search.SearchMatch 6 | import org.eclipse.jdt.core.search.SearchRequestor 7 | /** 8 | * contains the result of method search 9 | */ 10 | class MethodSearchRequestor extends SearchRequestor { 11 | val matchedElements = new mutable.ListBuffer[IJavaElement] 12 | override def acceptSearchMatch(searchMatch: SearchMatch) = { 13 | val element = searchMatch.getElement 14 | matchedElements += element.asInstanceOf[IJavaElement] 15 | } 16 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/hyperlink/RouteHyperlinkDetector.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.hyperlink 2 | 3 | import org.eclipse.jdt.core.IJavaElement 4 | import org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlink 5 | import org.eclipse.jdt.ui.actions.OpenAction 6 | import org.eclipse.jface.text.IRegion 7 | import org.eclipse.jface.text.ITextViewer 8 | import org.eclipse.jface.text.hyperlink.IHyperlink 9 | import org.eclipse.jface.text.hyperlink.IHyperlinkDetector 10 | import org.scalaide.play2.routeeditor.RouteAction 11 | import org.scalaide.play2.routeeditor.RouteEditor 12 | 13 | class RouteHyperlinkDetector(routeEditor: RouteEditor) extends IHyperlinkDetector { 14 | override def detectHyperlinks(textViewer: ITextViewer, region: IRegion, canShowMultipleHyperlinks: Boolean): Array[IHyperlink] = { 15 | routeEditor.getScalaProject.flatMap { 16 | scalaProject => 17 | RouteHyperlinkComputer.detectHyperlinks(scalaProject, textViewer.getDocument(), region, createJavaHyperlink) 18 | }.map(Array(_)).getOrElse(null) 19 | } 20 | 21 | protected def createJavaHyperlink(routeAction: RouteAction, method: IJavaElement): IHyperlink = { 22 | val openAction = new OpenAction( 23 | routeEditor.getEditorSite()) 24 | new JavaElementHyperlink(routeAction.region, 25 | openAction, method, false) 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/AbstractRouteScanner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.scalaide.core.lexical.AbstractScalaScanner 4 | import org.scalaide.ui.syntax.ScalaSyntaxClass 5 | 6 | import org.eclipse.jface.preference.IPreferenceStore 7 | import org.eclipse.jface.text.rules.RuleBasedScanner 8 | 9 | abstract class AbstractRouteScanner(defaultSyntax: ScalaSyntaxClass, prefStore: IPreferenceStore) extends RuleBasedScanner with AbstractScalaScanner { 10 | fDefaultReturnToken = getToken(defaultSyntax) 11 | override def preferenceStore = prefStore 12 | 13 | def getDefaultReturnToken = fDefaultReturnToken 14 | 15 | } 16 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/HTTPKeywords.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | object HTTPKeywords { 4 | final val Methods = Array("GET", "POST", "PUT", "PATCH", "HEAD", "DELETE", "OPTIONS").sorted 5 | } 6 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/MethodPackageRule.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.rules.ICharacterScanner 4 | import org.eclipse.jface.text.rules.IRule 5 | import org.eclipse.jface.text.rules.IToken 6 | import org.eclipse.jface.text.rules.Token 7 | /** 8 | * A rule for identifying a method name or package name 9 | */ 10 | class MethodPackageRule(packageToken: IToken, methodToken: IToken) extends IRule { 11 | sealed class PackageReadingState(i: Int) 12 | case object Middle extends PackageReadingState(0) 13 | case object NotFound extends PackageReadingState(2) 14 | case object PackageFound extends PackageReadingState(3) 15 | case object MethodFound extends PackageReadingState(4) 16 | 17 | override def evaluate(scanner: ICharacterScanner) = { 18 | var state: PackageReadingState = NotFound 19 | var r = scanner.read() 20 | var c = r.asInstanceOf[Char] 21 | var rCount = 1 22 | if (r != ICharacterScanner.EOF && Character.isLowerCase(c)) { 23 | state = Middle 24 | while (state == Middle) { 25 | r = scanner.read(); 26 | rCount += 1; 27 | c = r.asInstanceOf[Char]; 28 | if (r == ICharacterScanner.EOF) { 29 | state = MethodFound 30 | } 31 | if (c == '.') 32 | state = PackageFound // `.' IS inside package token 33 | else if (c == '(') { 34 | state = MethodFound 35 | scanner.unread() // `(' is NOT inside method token 36 | } 37 | } 38 | } 39 | state match { 40 | case NotFound => 41 | for (i <- 0 until rCount) { 42 | scanner.unread() 43 | } 44 | Token.UNDEFINED 45 | case PackageFound => 46 | packageToken 47 | case MethodFound => 48 | methodToken 49 | case _ => 50 | Token.UNDEFINED // impossible to reach! 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/RouteActionScanner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jdt.ui.text.IColorManager 4 | import org.eclipse.jface.preference.IPreferenceStore 5 | import org.eclipse.jface.text.rules.IRule 6 | import org.eclipse.jface.text.rules.IWordDetector 7 | import org.eclipse.jface.text.rules.WordRule 8 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.ACTION 9 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.ACTION_CLASS 10 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.ACTION_METHOD 11 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.ACTION_PACKAGE 12 | /** 13 | * scanner for action part of route file 14 | */ 15 | class RouteActionScanner(prefStore: IPreferenceStore) extends AbstractRouteScanner(ACTION, prefStore) { 16 | 17 | val packageToken = getToken(ACTION_PACKAGE); 18 | val classToken = getToken(ACTION_CLASS); 19 | val methodToken = getToken(ACTION_METHOD); 20 | val methodArgumentToken = fDefaultReturnToken 21 | 22 | val rules = Array[IRule]( 23 | // Add a rule for method argument 24 | new WordRule(new MethodArgumentDetector(), 25 | methodArgumentToken), 26 | // Add a rule for class 27 | new WordRule(new ClassDetector(), classToken), 28 | // Add a rule for method and package 29 | new MethodPackageRule(packageToken, methodToken)) 30 | 31 | setRules(rules); 32 | 33 | private class ClassDetector extends IWordDetector { 34 | 35 | override def isWordStart(c: Char) = { 36 | Character.isUpperCase(c) 37 | } 38 | 39 | override def isWordPart(c: Char) = { 40 | Character.isJavaIdentifierPart(c); 41 | } 42 | 43 | } 44 | 45 | private class MethodArgumentDetector extends IWordDetector { 46 | 47 | override def isWordStart(c: Char) = { 48 | c == '(' 49 | } 50 | 51 | override def isWordPart(c: Char) = { 52 | true 53 | } 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/RouteDocumentPartitioner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.TypedRegion 4 | 5 | import org.scalaide.play2.lexical.PlayDocumentPartitioner 6 | 7 | import RoutePartitions.ROUTE_DEFAULT 8 | import RoutePartitions.ROUTE_URI 9 | 10 | class RouteDocumentPartitioner(conservative: Boolean = false) extends PlayDocumentPartitioner(new RoutePartitionTokeniser, ROUTE_DEFAULT, conservative) { 11 | 12 | override def getLegalContentTypes: Array[String] = RoutePartitions.getTypes 13 | 14 | def uriPartitions: List[TypedRegion] = partitionRegions.filter(_.getType == ROUTE_URI) 15 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/RoutePartitions.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jface.text.IDocument 4 | 5 | object RoutePartitions { 6 | val ROUTE_PARTITIONING = "___route_partitioning" 7 | val ROUTE_URI = "__route_uri" 8 | val ROUTE_ACTION = "__route_action" 9 | val ROUTE_COMMENT = "__route_comment" 10 | val ROUTE_HTTP = "__route_http" 11 | val ROUTE_DEFAULT = IDocument.DEFAULT_CONTENT_TYPE 12 | 13 | val getTypes: Array[String] = 14 | Array(ROUTE_URI, ROUTE_ACTION, ROUTE_COMMENT, ROUTE_HTTP, ROUTE_DEFAULT); 15 | 16 | def isRouteAction(typeString: String): Boolean = typeString == ROUTE_ACTION 17 | } 18 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/lexical/RouteURIScanner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.lexical 2 | 3 | import org.eclipse.jdt.ui.text.IColorManager 4 | import org.eclipse.jface.preference.IPreferenceStore 5 | import org.eclipse.jface.text.rules.IRule 6 | import org.eclipse.jface.text.rules.IWordDetector 7 | import org.eclipse.jface.text.rules.WordRule 8 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.URI 9 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses.URI_DYNAMIC 10 | /** 11 | * scanner for URI part of route file 12 | */ 13 | class RouteURIScanner(prefStore: IPreferenceStore) extends AbstractRouteScanner(URI, prefStore) { 14 | def dynamic = getToken(URI_DYNAMIC) 15 | 16 | val rules = Array[IRule]( 17 | // Add a rule for dynamic with colon 18 | new WordRule(new DynamicColonDetector(), dynamic), 19 | // Add a rule for dynamic with star 20 | new WordRule(new DynamicStarDetector(), dynamic), 21 | // Add a rule for dynamic with dollar 22 | new WordRule(new DynamicDollarDetector(), dynamic), 23 | // Add a rule for static 24 | new WordRule(new StaticDetector(), fDefaultReturnToken)) 25 | setRules(rules); 26 | 27 | private class StaticDetector extends IWordDetector { 28 | override def isWordStart(c: Char) = { 29 | c == '/' 30 | } 31 | 32 | override def isWordPart(c: Char): Boolean = { 33 | for (w <- " \t\n") { 34 | if (c == w) 35 | return false; 36 | } 37 | return !(c == ':' || c == '*' || c == '$') 38 | } 39 | 40 | } 41 | 42 | private abstract class DynamicDetector(start: Char, whiteSpaces: Array[Char]) extends IWordDetector { 43 | def this(start: Char, whiteSpaces: String) = { 44 | this(start, whiteSpaces.toCharArray); 45 | } 46 | 47 | override def isWordStart(c: Char) = { 48 | c == start 49 | } 50 | 51 | override def isWordPart(c: Char): Boolean = { 52 | for (w <- whiteSpaces) { 53 | if (c == w) 54 | return false; 55 | } 56 | return true; 57 | } 58 | 59 | } 60 | 61 | private class DynamicColonDetector extends DynamicDetector(':', " \t\n") 62 | 63 | private class DynamicStarDetector extends DynamicDetector('*', " \t\n") 64 | 65 | private class DynamicDollarDetector extends DynamicDetector('$', " \t\n") 66 | } 67 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/properties/RouteColorPreferenceInitializer.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.properties 2 | import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.eclipse.jface.resource.StringConverter 5 | import org.eclipse.swt.graphics.RGB 6 | import org.scalaide.ui.syntax.ScalaSyntaxClass 7 | import org.scalaide.play2.PlayPlugin 8 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses._ 9 | 10 | class RouteColorPreferenceInitializer extends AbstractPreferenceInitializer { 11 | 12 | override def initializeDefaultPreferences() { 13 | doInitializeDefaultPreferences() 14 | } 15 | 16 | private def doInitializeDefaultPreferences() { 17 | val prefStore = PlayPlugin.preferenceStore 18 | setDefaultsForSyntaxClasses(prefStore) 19 | prefStore.setDefault(PlayPlugin.RouteFormatterMarginId, 3) // for formatter 20 | } 21 | 22 | private def setDefaultsForSyntaxClass( 23 | syntaxClass: ScalaSyntaxClass, 24 | foregroundRGB: RGB, 25 | enabled: Boolean = true, 26 | backgroundRGBOpt: Option[RGB] = None, 27 | bold: Boolean = false, 28 | italic: Boolean = false, 29 | strikethrough: Boolean = false, 30 | underline: Boolean = false)(implicit scalaPrefStore: IPreferenceStore) = 31 | { 32 | lazy val WHITE = new RGB(255, 255, 255) 33 | scalaPrefStore.setDefault(syntaxClass.enabledKey, enabled) 34 | scalaPrefStore.setDefault(syntaxClass.foregroundColorKey, StringConverter.asString(foregroundRGB)) 35 | val defaultBackgroundColor = StringConverter.asString(backgroundRGBOpt getOrElse WHITE) 36 | scalaPrefStore.setDefault(syntaxClass.backgroundColorKey, defaultBackgroundColor) 37 | scalaPrefStore.setDefault(syntaxClass.backgroundColorEnabledKey, backgroundRGBOpt.isDefined) 38 | scalaPrefStore.setDefault(syntaxClass.boldKey, bold) 39 | scalaPrefStore.setDefault(syntaxClass.italicKey, italic) 40 | scalaPrefStore.setDefault(syntaxClass.underlineKey, underline) 41 | } 42 | 43 | private def setDefaultsForSyntaxClasses(implicit scalaPrefStore: IPreferenceStore) { 44 | setDefaultsForSyntaxClass(COMMENT, new RGB(128, 128, 0)) 45 | setDefaultsForSyntaxClass(URI, new RGB(0, 0, 128)) 46 | setDefaultsForSyntaxClass(URI_DYNAMIC, new RGB(128, 128, 255)) 47 | setDefaultsForSyntaxClass(ACTION, new RGB(128, 0, 0)) 48 | setDefaultsForSyntaxClass(ACTION_PACKAGE, new RGB(196, 196, 196)) 49 | setDefaultsForSyntaxClass(ACTION_CLASS, new RGB(63, 46, 255)) 50 | setDefaultsForSyntaxClass(ACTION_METHOD, new RGB(0, 0, 0), italic = true) 51 | setDefaultsForSyntaxClass(DEFAULT, new RGB(0, 0, 0)) 52 | setDefaultsForSyntaxClass(HTTP_KEYWORD, new RGB(139, 10, 80), bold = true) 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/properties/RouteFormatterPreferencePage.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.properties 2 | 3 | import org.eclipse.jface.preference.FieldEditorPreferencePage 4 | import org.eclipse.jface.preference.IntegerFieldEditor 5 | import org.eclipse.ui.IWorkbench 6 | import org.eclipse.ui.IWorkbenchPreferencePage 7 | import org.scalaide.play2.PlayPlugin 8 | 9 | class RouteFormatterPreferencePage extends FieldEditorPreferencePage with IWorkbenchPreferencePage { 10 | 11 | setPreferenceStore(PlayPlugin.preferenceStore) 12 | 13 | override def createFieldEditors() { 14 | val marginField = new IntegerFieldEditor(PlayPlugin.RouteFormatterMarginId, "Number of spaces between columns", getFieldEditorParent) 15 | marginField.setValidRange(1, 10) 16 | addField(marginField) 17 | 18 | val formatOnSaveToggle = new org.eclipse.jface.preference.BooleanFieldEditor(PlayPlugin.RouteFormatterFormatOnSaveId, "Format on save", getFieldEditorParent) 19 | addField(formatOnSaveToggle); 20 | } 21 | 22 | def init(workbench: IWorkbench) {} 23 | 24 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/properties/RoutePreviewerFactoryConfiguration.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.properties 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.scalaide.ui.syntax.preferences.PreviewerFactoryConfiguration 5 | import org.scalaide.play2.routeeditor.RouteConfiguration 6 | import org.scalaide.play2.routeeditor.lexical.RouteDocumentPartitioner 7 | import java.util.HashMap 8 | import org.eclipse.jface.text.IDocumentPartitioner 9 | import org.scalaide.play2.routeeditor.lexical.RoutePartitions 10 | import org.eclipse.jface.text.IDocumentExtension3 11 | 12 | object RoutePreviewerFactoryConfiguration extends PreviewerFactoryConfiguration { 13 | 14 | def getConfiguration(preferenceStore: IPreferenceStore) = 15 | new RouteConfiguration(preferenceStore, null) 16 | 17 | def getDocumentPartitioners(): Map[String, IDocumentPartitioner] = 18 | Map((IDocumentExtension3.DEFAULT_PARTITIONING, new RouteDocumentPartitioner(true))) 19 | 20 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/routeeditor/properties/RouteSyntaxColoringPreferencePage.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.routeeditor.properties 2 | 3 | import org.scalaide.play2.routeeditor.RouteSyntaxClasses 4 | import org.scalaide.ui.syntax.preferences.BaseSyntaxColoringPreferencePage 5 | import org.scalaide.play2.PlayPlugin 6 | 7 | class RouteSyntaxColoringPreferencePage extends BaseSyntaxColoringPreferencePage( 8 | RouteSyntaxClasses.categories, 9 | RouteSyntaxClasses.routeOtherCategory, 10 | PlayPlugin.instance().getPreferenceStore, 11 | RouteSyntaxColoringPreferencePage.previewText, 12 | RoutePreviewerFactoryConfiguration) 13 | 14 | object RouteSyntaxColoringPreferencePage { 15 | val previewText = 16 | """#Route file 17 | |GET /static_part/:dynamic_part package1.package2.Class1.method(stringParameter, intParameter) 18 | |""".stripMargin 19 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/BracketAutoEditStrategy.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.eclipse.jface.text.DocumentCommand 5 | import org.eclipse.jface.text.IAutoEditStrategy 6 | import org.eclipse.jface.text.IDocument 7 | 8 | /** 9 | * Copied from scala-ide.core since the class has been removed. 10 | */ 11 | class BracketAutoEditStrategy(prefStore: IPreferenceStore) extends IAutoEditStrategy { 12 | 13 | def customizeDocumentCommand(document: IDocument, command: DocumentCommand) = { 14 | def ch(i: Int, c: Char) = { 15 | val o = command.offset + i 16 | o >= 0 && o < document.getLength && document.getChar(o) == c 17 | } 18 | 19 | def jumpOverClosingBrace() = { 20 | if (ch(0, '}')) { 21 | command.text = "" 22 | command.caretOffset = command.offset + 1 23 | } 24 | } 25 | 26 | def removeClosingBrace() = { 27 | if (ch(0, '{') && ch(1, '}')) { 28 | command.length = 2 29 | } 30 | } 31 | 32 | command.text match { 33 | case "}" => jumpOverClosingBrace() 34 | case "" => removeClosingBrace() 35 | case _ => 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/TemplateDocumentProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor 2 | 3 | import org.eclipse.jface.text.IDocument 4 | import org.eclipse.ui.editors.text.FileDocumentProvider 5 | import org.scalaide.play2.templateeditor.lexical.TemplateDocumentPartitioner 6 | 7 | class TemplateDocumentProvider extends FileDocumentProvider/* with IAnnotationModelFactory */{ 8 | protected override def createDocument(element: Object): IDocument = { 9 | val document = super.createDocument(element); 10 | if (document != null) { 11 | val partitioner = new TemplateDocumentPartitioner(true) 12 | partitioner.connect(document) 13 | document.setDocumentPartitioner(partitioner) 14 | } 15 | document 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/TemplateEditor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor 2 | 3 | import scala.collection.JavaConverters 4 | import org.eclipse.jdt.core.compiler.IProblem 5 | import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitDocumentProvider.ProblemAnnotation 6 | import org.eclipse.jface.text.Position 7 | import org.eclipse.jface.text.source.IAnnotationModel 8 | import org.eclipse.jface.text.source.IAnnotationModelExtension 9 | import org.eclipse.jface.text.source.IAnnotationModelExtension2 10 | import org.eclipse.jface.text.source.ISourceViewer 11 | import org.eclipse.jface.util.PropertyChangeEvent 12 | import org.eclipse.ui.editors.text.EditorsUI 13 | import org.eclipse.ui.texteditor.ChainedPreferenceStore 14 | import org.scalaide.play2.PlayPlugin 15 | import org.scalaide.ui.editor.SourceCodeEditor 16 | import org.scalaide.ui.editor.CompilationUnitProvider 17 | import org.eclipse.jface.preference.IPreferenceStore 18 | import org.eclipse.ui.editors.text.TextEditor 19 | import org.eclipse.jface.text.source.IVerticalRuler 20 | import org.eclipse.swt.widgets.Composite 21 | import org.scalaide.play2.util.StoredEditorUtils 22 | 23 | trait AbstractTemplateEditor extends SourceCodeEditor { self: TextEditor => 24 | 25 | override protected type UnderlyingCompilationUnit = TemplateCompilationUnit 26 | 27 | override val compilationUnitProvider: CompilationUnitProvider[UnderlyingCompilationUnit] = new TemplateCompilationUnitProvider(false) 28 | } 29 | 30 | class TemplateEditor extends TextEditor with AbstractTemplateEditor { 31 | 32 | override protected lazy val preferenceStore: IPreferenceStore = new ChainedPreferenceStore(Array((EditorsUI.getPreferenceStore()), PlayPlugin.preferenceStore)) 33 | private val sourceViewConfiguration = new TemplateConfiguration(preferenceStore, this) 34 | private val documentProvider = new TemplateDocumentProvider() 35 | 36 | setSourceViewerConfiguration(sourceViewConfiguration); 37 | setPreferenceStore(preferenceStore) 38 | setDocumentProvider(documentProvider); 39 | 40 | override def handlePreferenceStoreChanged(event: PropertyChangeEvent) = { 41 | sourceViewConfiguration.propertyChange(event) 42 | super.handlePreferenceStoreChanged(event) 43 | } 44 | 45 | override def affectsTextPresentation(event: PropertyChangeEvent): Boolean = { 46 | // TODO: more precise filtering 47 | true 48 | } 49 | 50 | override def editorSaved() = { 51 | super.editorSaved() 52 | sourceViewConfiguration.strategy.reconcile(null) 53 | } 54 | override def createSourceViewer(parent: Composite, verticalRuler: IVerticalRuler, styles: Int): ISourceViewer = { 55 | val sourceViewer = super.createSourceViewer(parent, verticalRuler, styles) 56 | StoredEditorUtils.storeEditorInViewer(sourceViewer, this) 57 | sourceViewer 58 | } 59 | } 60 | 61 | object TemplateEditor { 62 | /** The annotation types shown when hovering on the left-side ruler (or in the status bar). */ 63 | val annotationsShownInHover = Set( 64 | "org.eclipse.jdt.ui.error", "org.eclipse.jdt.ui.warning", "org.eclipse.jdt.ui.info") 65 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/TemplateSyntaxClasses.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor 2 | 3 | import org.scalaide.ui.syntax.ScalaSyntaxClass 4 | import org.scalaide.ui.syntax.ScalaSyntaxClass.Category 5 | import org.scalaide.ui.syntax.ScalaSyntaxClasses 6 | 7 | object TemplateSyntaxClasses { 8 | val DEFAULT = ScalaSyntaxClass("Default", "template.default") 9 | val PLAIN = ScalaSyntaxClass("Plain", "template.plain") 10 | val COMMENT = ScalaSyntaxClass("Template Comment", "template.comment") 11 | val MAGIC_AT = ScalaSyntaxClass("Template Magic @", "template.at") 12 | val BRACE = ScalaSyntaxClass("Template Brace", "template.brace") 13 | 14 | val scalaCategory = Category("Scala", List(ScalaSyntaxClasses.KEYWORD, 15 | ScalaSyntaxClasses.STRING, 16 | ScalaSyntaxClasses.DEFAULT, 17 | ScalaSyntaxClasses.OPERATOR, 18 | ScalaSyntaxClasses.BRACKET, 19 | ScalaSyntaxClasses.RETURN, 20 | ScalaSyntaxClasses.SYMBOL, 21 | ScalaSyntaxClasses.MULTI_LINE_STRING, 22 | ScalaSyntaxClasses.NUMBER_LITERAL)) 23 | 24 | val htmlCategory = Category("HTML", List(ScalaSyntaxClasses.XML_COMMENT, 25 | ScalaSyntaxClasses.XML_ATTRIBUTE_VALUE, 26 | ScalaSyntaxClasses.XML_ATTRIBUTE_NAME, 27 | ScalaSyntaxClasses.XML_ATTRIBUTE_EQUALS, 28 | ScalaSyntaxClasses.XML_TAG_DELIMITER, 29 | ScalaSyntaxClasses.XML_TAG_NAME, 30 | ScalaSyntaxClasses.XML_PI, 31 | ScalaSyntaxClasses.XML_CDATA_BORDER)) 32 | 33 | val commentsCategory = Category("Comments", List(ScalaSyntaxClasses.SINGLE_LINE_COMMENT, 34 | ScalaSyntaxClasses.MULTI_LINE_COMMENT, 35 | ScalaSyntaxClasses.SCALADOC, 36 | COMMENT)) 37 | 38 | val otherCategory = Category("Other", List( 39 | DEFAULT, PLAIN, MAGIC_AT, BRACE)) 40 | 41 | val categories = List(scalaCategory, htmlCategory, commentsCategory, otherCategory) 42 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/compiler/CompilerUsing.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.compiler 2 | 3 | import java.io.File 4 | 5 | import scala.io.Codec 6 | import scala.util.Failure 7 | import scala.util.Try 8 | 9 | import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities 10 | import org.scalaide.core.compiler.ScalaCompilationProblem 11 | import org.scalaide.logging.HasLogger 12 | import org.scalaide.play2.PlayProject 13 | import org.scalaide.play2.properties.PlayPreferences.PlayVersion 14 | import org.scalaide.play2.templateeditor.processing.GeneratedSource 15 | import org.scalaide.play2.templateeditor.processing.TemplateProcessingProvider 16 | 17 | /** 18 | * a helper for using template compiler 19 | */ 20 | object CompilerUsing extends HasLogger { 21 | /** 22 | * invokes compile method of template compiler and returns generated source object or 23 | * in the case of error, returns appropriate exception 24 | */ 25 | def compileTemplateToScalaVirtual(content: String, source: File, playProject: PlayProject, inclusiveDot: Boolean): Try[GeneratedSource] = { 26 | val sourcePath = playProject.sourceDir.getAbsolutePath() 27 | if (source.getAbsolutePath().indexOf(sourcePath) == -1) 28 | logger.debug(s"Template file '${source.getAbsolutePath}' must be located in '$sourcePath' or one of its subfolders!") 29 | 30 | val extension = source.getName.split('.').last 31 | 32 | val playVersion = if (playProject.cachedPreferenceStore.getString(PlayVersion).isEmpty()) 33 | None 34 | else 35 | Some(playProject.cachedPreferenceStore.getString(PlayVersion)) 36 | 37 | TemplateProcessingProvider.templateProcessing(playVersion).compile( 38 | content, 39 | source, 40 | playProject.sourceDir, 41 | playProject.templateImports(extension), 42 | Codec.default, 43 | inclusiveDot).recoverWith { 44 | case ex: Exception => { 45 | val error = s"Caught unknown exception: '${ex.getMessage()}'\n${ex.getStackTraceString}" 46 | Failure(TemplateToScalaCompilationError(source, error, 0, 0, 0)) 47 | } 48 | } 49 | } 50 | 51 | } 52 | 53 | case class TemplateToScalaCompilationError(source: File, message: String, offset: Int, line: Int, column: Int) extends RuntimeException(message) { 54 | override def toString = source.getName + ": " + message + offset + " " + line + "." + column 55 | 56 | import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities 57 | 58 | def toProblem: ScalaCompilationProblem = 59 | ScalaCompilationProblem( 60 | source.getAbsolutePath().toString, 61 | ProblemSeverities.Error, 62 | message, 63 | Math.max(offset - 1, 0), 64 | Math.max(offset - 1, 0), 65 | line, 66 | column) 67 | } 68 | 69 | object PositionHelper { 70 | def convertLineColumnToOffset(source: File, line: Int, column: Int): Int = { 71 | convertLineColumnToOffset(scala.io.Source.fromFile(source).mkString, line, column) 72 | } 73 | 74 | def convertLineColumnToOffset(content: String, line: Int, column: Int): Int = { 75 | // splitting the string will cause some problems 76 | var offset = 0 77 | for (i <- 1 until line) { 78 | offset = content.indexOf("\n", offset) + 1 79 | } 80 | offset += column - 1 81 | offset 82 | } 83 | 84 | def mapSourcePosition(matrix: Seq[(Int, Int)], sourcePosition: Int): Int = { 85 | val sortedMatrix = matrix.sortBy(_._2) 86 | sortedMatrix.indexWhere(p => p._2 > sourcePosition) match { 87 | case 0 => 0 88 | case i if i > 0 => { 89 | val pos = sortedMatrix(i - 1) 90 | pos._1 + (sourcePosition - pos._2) 91 | } 92 | case _ => { 93 | val pos = sortedMatrix.takeRight(1)(0) 94 | pos._1 + (sourcePosition - pos._2) 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/hyperlink/TemplateDeclarationHyperlinkDetector.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.hyperlink 2 | 3 | import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor 4 | import org.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlink 5 | import org.eclipse.jdt.ui.actions.OpenAction 6 | import org.eclipse.jface.text.IRegion 7 | import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector 8 | import org.eclipse.jface.text.hyperlink.IHyperlink 9 | import org.eclipse.ui.texteditor.ITextEditor 10 | import org.scalaide.util.ScalaWordFinder 11 | import org.scalaide.core.compiler.InteractiveCompilationUnit 12 | import org.eclipse.jdt.internal.core.JavaProject 13 | import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner 14 | import org.scalaide.play2.templateeditor.lexical.TemplatePartitions 15 | import org.eclipse.jface.text.Region 16 | import org.scalaide.play2.templateeditor.compiler.PositionHelper 17 | import org.scalaide.play2.templateeditor.TemplateCompilationUnit 18 | import org.scalaide.ui.editor.SourceConfiguration 19 | 20 | 21 | object TemplateDeclarationHyperlinkDetector { 22 | def apply()= SourceConfiguration.scalaDeclarationDetector 23 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/lexical/HtmlTagScanner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import org.scalaide.core.internal.lexical.XmlTagScanner 4 | import org.eclipse.jdt.ui.text.IColorManager 5 | import org.eclipse.jface.preference.IPreferenceStore 6 | import org.eclipse.jface.text.IDocument 7 | import org.eclipse.jface.text.rules.IToken 8 | import org.scalaide.ui.syntax.ScalaSyntaxClasses._ 9 | 10 | /** A special code scanner for Play templates. It only mark the beginning and end quotes as 11 | */ 12 | class HtmlTagScanner(preferenceStore: IPreferenceStore) extends XmlTagScanner(preferenceStore) { 13 | import XmlTagScanner._ 14 | 15 | var start: Int = -1 16 | 17 | override def setRange(document: IDocument, offset: Int, length: Int) { 18 | super.setRange(document, offset, length) 19 | this.start = offset 20 | } 21 | 22 | private def ch = if (pos > end) EOF else document.getChar(pos) 23 | 24 | override def nextToken(): IToken = { 25 | if (pos == start && pos != -1) { 26 | ch match { 27 | case '\'' | '\"' => { 28 | tokenOffset = start 29 | tokenLength = 1 30 | pos += 1 31 | return getToken(XML_ATTRIBUTE_VALUE) 32 | } 33 | case _ => 34 | } 35 | } 36 | super.nextToken 37 | } 38 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/lexical/TemplateDefaultScanner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import org.eclipse.jdt.ui.text.IColorManager 4 | import org.eclipse.jface.preference.IPreferenceStore 5 | import org.eclipse.jface.text.rules.IRule 6 | import org.eclipse.jface.text.rules.IWordDetector 7 | import org.eclipse.jface.text.rules.WordRule 8 | import org.scalaide.play2.routeeditor.lexical.AbstractRouteScanner 9 | import org.scalaide.play2.templateeditor.TemplateSyntaxClasses 10 | 11 | class TemplateDefaultScanner(prefStore: IPreferenceStore) extends AbstractRouteScanner(TemplateSyntaxClasses.DEFAULT, prefStore) { 12 | val atToken = getToken(TemplateSyntaxClasses.MAGIC_AT); 13 | val braceToken = getToken(TemplateSyntaxClasses.BRACE); 14 | 15 | val rules = Array[IRule]( 16 | new WordRule(new OperatorDetector('@'), 17 | atToken), 18 | new WordRule(new OperatorDetector('{', '}'), braceToken)) 19 | 20 | setRules(rules); 21 | 22 | private class OperatorDetector(operators: Char*) extends IWordDetector { 23 | 24 | override def isWordStart(c: Char) = { 25 | operators exists (_ == c) 26 | } 27 | 28 | override def isWordPart(c: Char) = { 29 | false 30 | } 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/lexical/TemplateDocumentPartitioner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import org.scalaide.play2.lexical.PlayDocumentPartitioner 4 | import TemplatePartitions.TEMPLATE_COMMENT 5 | import TemplatePartitions.TEMPLATE_DEFAULT 6 | import TemplatePartitions.TEMPLATE_SCALA 7 | import org.eclipse.jface.text.ITypedRegion 8 | 9 | class TemplateDocumentPartitioner(conservative: Boolean = false) extends PlayDocumentPartitioner(new TemplatePartitionTokeniser, TemplatePartitions.TEMPLATE_DEFAULT, conservative) { 10 | 11 | import TemplateDocumentPartitioner._ 12 | 13 | def getLegalContentTypes = LEGAL_CONTENT_TYPES 14 | 15 | override def getPartition(offset: Int, preferOpenPartitions: Boolean): ITypedRegion = { 16 | val region = super.getPartition(offset, preferOpenPartitions) 17 | if (preferOpenPartitions) 18 | if (region.getOffset == offset && region.getType != defaultPartition) 19 | if (offset > 0) { 20 | val previousRegion = getPartition(offset - 1) 21 | // FIXME: This doesn't make any sense to me. We should prioritize the previous 22 | // partition only if it's meaningful, i.e., if it is NOT the default partitioning. 23 | // Hence, I'm wondering if the template editor actually relies on this logic, as 24 | // it seems pretty useless and could actually cause some completion proposals to 25 | // no show up because the default partitioning (instead of a specific one) is returned. 26 | if (previousRegion.getType == defaultPartition) 27 | return previousRegion 28 | } 29 | region 30 | } 31 | } 32 | 33 | object TemplateDocumentPartitioner { 34 | 35 | private val LEGAL_CONTENT_TYPES = Array[String]( 36 | TEMPLATE_DEFAULT, TEMPLATE_SCALA, TEMPLATE_COMMENT) 37 | 38 | val NO_PARTITION_AT_ALL = "__no_partition_at_all" 39 | 40 | final val EOF = '\u001A' 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/lexical/TemplateParsing.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import scala.util.parsing.input.CharSequenceReader 4 | import scala.util.parsing.input.OffsetPosition 5 | import scala.util.parsing.input.Positional 6 | 7 | import org.scalaide.play2.templateeditor.processing.TemplateProcessingProvider 8 | 9 | /** 10 | * A helper for using template parser 11 | */ 12 | object TemplateParsing { 13 | implicit def stringToCharSeq(str: String) = new CharSequenceReader(str) 14 | 15 | sealed abstract class PlayTemplate(input: Positional, kind: String) { 16 | val offset = input.pos match { 17 | case offsetPosition: OffsetPosition => 18 | offsetPosition.offset 19 | case _ => 20 | -1 21 | } 22 | val length = TemplateProcessingProvider.templateProcessing().length(input) 23 | 24 | override def toString = kind + "[" + offset + " - " + length + "]: " + input 25 | } 26 | case class ScalaCode(input: Positional) extends PlayTemplate(input, "sc") 27 | case class DefaultCode(input: Positional) extends PlayTemplate(input, "df") 28 | case class CommentCode(input: Positional) extends PlayTemplate(input, "cm") 29 | 30 | /** 31 | * Returns list of different types of region of the template code 32 | */ 33 | def handleTemplateCode(templateCode: String) = 34 | TemplateProcessingProvider.templateProcessing().parse(templateCode) 35 | } 36 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/lexical/TemplatePartitions.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.lexical 2 | 3 | import org.eclipse.jface.text.IDocument 4 | 5 | 6 | object TemplatePartitions { 7 | val TEMPLATE_PARTITIONING = "___template_partitioning"; 8 | val TEMPLATE_DEFAULT = IDocument.DEFAULT_CONTENT_TYPE 9 | val TEMPLATE_SCALA = "__template_scala" 10 | val TEMPLATE_COMMENT = "__template_comment" 11 | val TEMPLATE_PLAIN = "__template_plain" 12 | val TEMPLATE_TAG = "__template_tag" 13 | 14 | def getTypes() = { 15 | Array(TEMPLATE_DEFAULT, TEMPLATE_SCALA, TEMPLATE_COMMENT, TEMPLATE_TAG, TEMPLATE_PLAIN); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/processing/TemplateProcessing.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.processing 2 | 3 | import java.io.File 4 | 5 | import scala.io.Codec 6 | import scala.util.Try 7 | import scala.util.parsing.input.Positional 8 | 9 | import org.scalaide.play2.templateeditor.lexical.TemplateParsing.PlayTemplate 10 | 11 | /** 12 | * Thought as the interface to template parser and compiler as long as Twirl library does not define 13 | * the abstraction for these two functionalities. Implemented by extensions of [[TemplateProcessingProvider.ExtensionPointId]] 14 | */ 15 | trait TemplateProcessing { 16 | /** 17 | * Parses and returns list of different types of region of the template code. 18 | * @param templateCode template code to parse 19 | * @return a list of [[PlayTemplate]] objects 20 | */ 21 | def parse(templateCode: String): List[PlayTemplate] 22 | 23 | /** 24 | * Gets length of parsed token. 25 | * @param token as [[Positional]] 26 | * @return length of token 27 | */ 28 | def length(input: Positional): Int 29 | 30 | /** 31 | * Invokes compile method of template compiler and returns generated source object or 32 | * in the case of error, returns appropriate exception. 33 | * @param content with template code 34 | * @param source keeps the template file 35 | * @param sourceDirectory 36 | * @param additionalImports 37 | * @param codec to decode charset used in template 38 | * @param inclusiveDot 39 | * @return generated scala source 40 | */ 41 | def compile(content: String, source: File, sourceDirectory: File, additionalImports: String, codec: Codec, inclusiveDot: Boolean): Try[GeneratedSource] 42 | } 43 | 44 | trait GeneratedSource { 45 | def content: String 46 | def matrix: Seq[(Int, Int)] 47 | def mapPosition(generatedPosition: Int): Int 48 | } 49 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/processing/TemplateProcessingProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.processing 2 | 3 | import org.eclipse.core.runtime.RegistryFactory 4 | import org.scalaide.logging.HasLogger 5 | import org.scalaide.play2.properties.PlayPreferences 6 | 7 | object TemplateProcessingProvider extends HasLogger { 8 | val ExtensionPointId = "org.scalaide.play2.template.processing" 9 | 10 | def templateProcessing(templateVersion: Option[String] = None): TemplateProcessing = { 11 | val extensions = RegistryFactory.getRegistry.getConfigurationElementsFor(ExtensionPointId) 12 | val playVersion = templateVersion.orElse(TemplateVersionExhibitor.get.flatMap { version => 13 | if (version.isEmpty) None else Some(version) 14 | }).orElse { 15 | eclipseLog.warn(s"Cannot find template version. Dropped to default ${PlayPreferences.DefaultPlayVersion}.") 16 | Some(PlayPreferences.DefaultPlayVersion) 17 | } 18 | val version = playVersion.flatMap { pVer => 19 | extensions.find { 20 | _.getChildren("version").map { 21 | _.getAttribute("supports") 22 | }.contains(pVer) 23 | } 24 | } 25 | if (version.nonEmpty) 26 | version.get.createExecutableExtension("class").asInstanceOf[TemplateProcessing] 27 | else 28 | throw new IllegalStateException(s"Cannot find template processing for Play version: ${playVersion.getOrElse("version not found")}.") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/processing/TemplateVersionExhibitor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.processing 2 | 3 | object TemplateVersionExhibitor { 4 | private val templateVersionStock: ThreadLocal[Option[String]] = 5 | new ThreadLocal[Option[String]] { 6 | override protected def initialValue: Option[String] = None 7 | } 8 | 9 | def get: Option[String] = templateVersionStock.get 10 | 11 | def set(templateVersion: Option[String]): Unit = templateVersionStock.set(templateVersion) 12 | 13 | def clean(): Unit = templateVersionStock.remove() 14 | } 15 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/processing/TemplateVersionExtractor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.processing 2 | 3 | import org.eclipse.core.resources.IFile 4 | import org.scalaide.play2.PlayPlugin 5 | import org.scalaide.play2.properties.PlayPreferences 6 | 7 | object TemplateVersionExtractor { 8 | def fromIFile(resource: IFile): Option[String] = 9 | PlayPlugin.instance().asPlayProject(resource.getProject).flatMap { project => 10 | val templateVersion = project.cachedPreferenceStore.getString(PlayPreferences.PlayVersion) 11 | if (templateVersion.isEmpty()) 12 | None 13 | else 14 | Some(templateVersion) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/properties/TemplatePreviewerFactoryConfiguration.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.properties 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.scalaide.play2.templateeditor.TemplateConfiguration 5 | import org.scalaide.play2.templateeditor.lexical.TemplateDocumentPartitioner 6 | import org.scalaide.ui.syntax.preferences.PreviewerFactoryConfiguration 7 | import org.scalaide.play2.templateeditor.lexical.TemplatePartitions 8 | import java.util.HashMap 9 | import org.eclipse.jface.text.IDocumentPartitioner 10 | import org.eclipse.jface.text.IDocumentExtension3 11 | 12 | object TemplatePreviewerFactoryConfiguration extends PreviewerFactoryConfiguration { 13 | 14 | def getConfiguration(preferenceStore: IPreferenceStore) = 15 | new TemplateConfiguration(preferenceStore, null) 16 | 17 | def getDocumentPartitioners(): Map[String, IDocumentPartitioner] = 18 | Map((IDocumentExtension3.DEFAULT_PARTITIONING, new TemplateDocumentPartitioner(true))) 19 | 20 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/properties/TemplateSyntaxColoringPreferencePage.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.properties 2 | 3 | import org.scalaide.ui.syntax.preferences.BaseSyntaxColoringPreferencePage 4 | import org.scalaide.play2.templateeditor.TemplateSyntaxClasses 5 | import org.scalaide.play2.PlayPlugin 6 | 7 | 8 | class TemplateSyntaxColoringPreferencePage extends BaseSyntaxColoringPreferencePage( 9 | TemplateSyntaxClasses.categories, 10 | TemplateSyntaxClasses.scalaCategory, 11 | PlayPlugin.instance().getPreferenceStore, 12 | TemplateSyntaxColoringPreferencePage.previewText, 13 | TemplatePreviewerFactoryConfiguration) 14 | 15 | 16 | 17 | object TemplateSyntaxColoringPreferencePage { 18 | 19 | val previewText = 20 | """@* Template Comment *@ 21 | |@(param: String, items: List[Item]) 22 | | 23 | |@{ 24 | | class A { 25 | | val b = "some string" 26 | | val n = 12.3 27 | | println("sym" + 'sym) 28 | | } 29 | | 30 | | new A 31 | |} 32 | |@items.foreach { item => 33 | | @{return item} 34 | |} 35 | | 36 | |""".stripMargin 37 | 38 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/reconciler/TemplateReconcilingStrategy.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.reconciler 2 | 3 | import org.eclipse.jface.text.DocumentEvent 4 | import org.eclipse.jface.text.IDocumentListener 5 | import org.scalaide.ui.editor.ReconcilingStrategy 6 | import org.scalaide.ui.editor.SourceCodeEditor 7 | import org.scalaide.play2.templateeditor.AbstractTemplateEditor 8 | 9 | private class TemplateReconcilingStrategy(templateEditor: SourceCodeEditor, documentListener: IDocumentListener) extends ReconcilingStrategy(templateEditor, documentListener) 10 | 11 | object TemplateReconcilingStrategy { 12 | 13 | def apply(templateEditor: AbstractTemplateEditor): ReconcilingStrategy = new TemplateReconcilingStrategy(templateEditor, new Reloader(templateEditor)) 14 | 15 | private class Reloader(templateEditor: AbstractTemplateEditor) extends IDocumentListener { 16 | def documentChanged(event: DocumentEvent) { 17 | templateEditor.compilationUnitProvider.fromEditor(templateEditor).scheduleReconcile(event.getText.toCharArray) 18 | } 19 | 20 | def documentAboutToBeChanged(event: DocumentEvent) {} 21 | } 22 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/ContentTypeIdForScala.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse 2 | 3 | object ContentTypeIdForScala { 4 | val ContentTypeID_Scala = "org.scalaide.play2.templateSource" 5 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/TemplateActionContributor.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse 2 | 3 | import org.eclipse.wst.html.ui.internal.edit.ui.ActionContributorHTML 4 | 5 | class TemplateActionContributor extends ActionContributorHTML { 6 | // Add refactoring actions ("RetargetTextEditorAction") here if needed 7 | 8 | override protected def getExtensionIDs(): Array[String] = 9 | Array(ContentTypeIdForScala.ContentTypeID_Scala, "org.eclipse.wst.sse.ui.StructuredTextEditor") 10 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/TemplateContentDescriber.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse 2 | 3 | import java.io.BufferedReader 4 | import java.io.InputStreamReader 5 | 6 | import scala.annotation.tailrec 7 | 8 | import org.eclipse.core.runtime.content.IContentDescriber 9 | import org.eclipse.core.runtime.content.IContentDescription 10 | 11 | /** 12 | * Detect a Play template file if it starts with `@(` or `@*`. 13 | */ 14 | class TemplateContentDescriber extends IContentDescriber { 15 | 16 | override def describe(contents: java.io.InputStream, description: IContentDescription) = { 17 | 18 | import IContentDescriber._ 19 | 20 | @tailrec 21 | def checkFirstNonEmptyLine(reader: BufferedReader): Int = { 22 | val line = reader.readLine() 23 | if (line == null) 24 | INDETERMINATE 25 | else { 26 | val trimmedLine = line.trim 27 | trimmedLine.length() match { 28 | case 0 => 29 | checkFirstNonEmptyLine(reader) 30 | case 1 => 31 | INVALID 32 | case _ => 33 | val c0 = trimmedLine.charAt(0) 34 | val c1 = trimmedLine.charAt(1) 35 | if (c0 == '@' && (c1 == '*' || c1 == '(')) 36 | IContentDescriber.VALID 37 | else 38 | IContentDescriber.INVALID 39 | } 40 | } 41 | } 42 | 43 | checkFirstNonEmptyLine(new BufferedReader(new InputStreamReader(contents, "UTF-8"))) 44 | } 45 | 46 | override def getSupportedOptions() = Array() 47 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/hyperlink/StructuredTemplateDeclarationHyperlinkDetector.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.hyperlink 2 | 3 | import org.eclipse.jface.text.IRegion 4 | import org.eclipse.jface.text.ITextViewer 5 | import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector 6 | import org.eclipse.jface.text.hyperlink.IHyperlink 7 | import org.scalaide.play2.templateeditor.hyperlink.TemplateDeclarationHyperlinkDetector 8 | import org.scalaide.play2.util.StoredEditorUtils 9 | 10 | 11 | class StructuredTemplateDeclarationHyperlinkDetector extends AbstractHyperlinkDetector { 12 | 13 | /** We create a new detector every time because we need to set the context (the corresponding editor) only once. 14 | * (setContext throws an exception if it's called more than once). We could force a way to initialize this only 15 | * once at the expense of additional state in this class, but seems overkill. 16 | * 17 | * Since the detector is a lightweight class (only one field), we take this approach. 18 | */ 19 | private def templateDeclHyperlinkDetector() = TemplateDeclarationHyperlinkDetector() 20 | 21 | final override def detectHyperlinks(viewer: ITextViewer, currentSelection: IRegion, canShowMultipleHyperlinks: Boolean): Array[IHyperlink] = { 22 | // make sure the context is correct 23 | val detector = templateDeclHyperlinkDetector 24 | StoredEditorUtils.getEditorOfViewer(viewer: ITextViewer).map(detector.setContext) 25 | detector.detectHyperlinks(viewer, currentSelection, canShowMultipleHyperlinks) 26 | } 27 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/lexical/TemplateStructuredTextPartitioner.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.lexical 2 | 3 | import org.eclipse.jface.text.DocumentEvent 4 | import org.eclipse.jface.text.IDocument 5 | import org.eclipse.jface.text.IDocumentPartitioner 6 | import org.eclipse.wst.html.core.internal.text.StructuredTextPartitionerForHTML 7 | import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion 8 | import org.eclipse.wst.sse.core.internal.text.rules.StructuredTextPartitioner 9 | import org.scalaide.play2.templateeditor.TemplateSyntaxClasses 10 | import org.scalaide.play2.templateeditor.lexical.TemplateDocumentPartitioner 11 | import org.scalaide.play2.templateeditor.lexical.TemplatePartitions 12 | import org.eclipse.jface.text.IDocumentPartitionerExtension2 13 | import org.eclipse.jface.text.ITypedRegion 14 | 15 | class TemplateStructuredTextPartitioner extends StructuredTextPartitioner with IDocumentPartitionerExtension2 { 16 | 17 | private val htmlPartitioner: StructuredTextPartitionerForHTML = new StructuredTextPartitionerForHTML 18 | 19 | override def connect(document: IDocument) = { 20 | super.connect(document) 21 | htmlPartitioner.connect(document) 22 | } 23 | 24 | override def disconnect() = { 25 | super.disconnect() 26 | htmlPartitioner.disconnect() 27 | } 28 | 29 | override def documentChanged(event: DocumentEvent): Boolean = { 30 | super.documentChanged(event) 31 | } 32 | 33 | override def computePartitioning(offset: Int, length: Int) = { 34 | htmlPartitioner.computePartitioning(offset, length) 35 | super.computePartitioning(offset, length) 36 | } 37 | 38 | override def getDefaultPartitionType() = { 39 | TemplatePartitions.TEMPLATE_DEFAULT 40 | } 41 | 42 | override def getPartitionType(region: ITextRegion, offset: Int) = { 43 | region match { 44 | case scalaRegion: TemplateTextRegion => scalaRegion.syntaxClass match { 45 | case TemplateSyntaxClasses.COMMENT => TemplatePartitions.TEMPLATE_COMMENT 46 | case TemplateSyntaxClasses.MAGIC_AT => TemplatePartitions.TEMPLATE_PLAIN 47 | case TemplateSyntaxClasses.BRACE => TemplatePartitions.TEMPLATE_PLAIN 48 | case _ => TemplatePartitions.TEMPLATE_SCALA 49 | } 50 | case _ => htmlPartitioner.getPartitionType(region, offset) 51 | } 52 | } 53 | 54 | override protected def setInternalPartition(offset: Int, length: Int, tpe: String) = { 55 | val region = htmlPartitioner.createPartition(offset, length, tpe) 56 | super.setInternalPartition(region.getOffset, region.getLength, region.getType) 57 | } 58 | 59 | override def newInstance(): IDocumentPartitioner = { 60 | val instance = new TemplateStructuredTextPartitioner 61 | instance.connect(fStructuredDocument) 62 | instance 63 | } 64 | 65 | /* IDocumentPartitionerExtension2 methods */ 66 | 67 | override def getManagingPositionCategories(): Array[String] = null 68 | 69 | override def getContentType(offset: Int, preferOpenPartitions: Boolean): String = 70 | getPartition(offset, preferOpenPartitions).getType() 71 | 72 | override def computePartitioning(offset: Int, length: Int, includeZeroLengthPartitions: Boolean): Array[ITypedRegion] = 73 | computePartitioning(offset, length) 74 | 75 | override def getPartition(offset: Int, preferOpenPartitions: Boolean): ITypedRegion = { 76 | val partition = getPartition(offset) 77 | if (preferOpenPartitions && partition.getOffset() == offset && offset > 0) { 78 | getPartition(offset - 1) 79 | } 80 | else partition 81 | } 82 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/lexical/TemplateTextRegion.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.lexical 2 | 3 | import org.scalaide.ui.syntax.ScalaSyntaxClass 4 | import org.eclipse.wst.sse.core.internal.parser.ContextRegion 5 | 6 | case class TemplateTextRegion(syntaxClass: ScalaSyntaxClass, newStart: Int, newTextLength: Int, newLength: Int) 7 | extends ContextRegion(syntaxClass.displayName, newStart, newTextLength, newLength) -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/model/TemplateAdapterFactoryProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.model 2 | 3 | import org.eclipse.wst.html.ui.internal.contentoutline.JFaceNodeAdapterFactoryForHTML 4 | import org.eclipse.wst.jsdt.web.core.javascript.JsTranslationAdapterFactory 5 | import org.eclipse.wst.sse.core.internal.ltk.modelhandler.IDocumentTypeHandler 6 | import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel 7 | import org.eclipse.wst.sse.ui.internal.contentoutline.IJFaceNodeAdapter 8 | import org.eclipse.wst.sse.ui.internal.provisional.registry.AdapterFactoryProvider 9 | import org.eclipse.wst.sse.ui.internal.util.Assert 10 | 11 | class TemplateAdapterFactoryProvider extends AdapterFactoryProvider { 12 | 13 | override def addAdapterFactories(structuredModel: IStructuredModel) = { 14 | val factoryRegistry = structuredModel.getFactoryRegistry() 15 | Assert.isNotNull(factoryRegistry, "Program error: client caller must ensure model has factory registry") 16 | if (factoryRegistry.getFactoryFor(classOf[IJFaceNodeAdapter]) == null) { 17 | factoryRegistry.addFactory(new JFaceNodeAdapterFactoryForHTML) 18 | } 19 | if (factoryRegistry.getFactoryFor(classOf[org.eclipse.wst.jsdt.web.core.javascript.IJsTranslation]) == null) { 20 | factoryRegistry.addFactory(new JsTranslationAdapterFactory) 21 | } 22 | } 23 | 24 | override def isFor(contentTypeDescription: IDocumentTypeHandler) = contentTypeDescription match { 25 | case _: TemplateModelHandler => true 26 | case _ => false 27 | } 28 | 29 | override def reinitializeFactories(structuredModel: IStructuredModel) = { } 30 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/model/TemplateDocumentLoader.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.model 2 | 3 | import org.eclipse.wst.html.core.internal.encoding.HTMLDocumentLoader 4 | import org.eclipse.wst.sse.core.internal.ltk.parser.RegionParser 5 | import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion 6 | import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocument 7 | import org.eclipse.wst.xml.core.internal.parser.XMLStructuredDocumentReParser 8 | import org.scalaide.play2.templateeditor.processing.TemplateVersionExhibitor 9 | import org.scalaide.play2.templateeditor.sse.lexical.TemplateRegionParser 10 | import org.scalaide.play2.templateeditor.sse.lexical.TemplateStructuredTextPartitioner 11 | 12 | class TemplateDocumentLoader extends HTMLDocumentLoader { 13 | 14 | override def newEncodedDocument() = { 15 | val structuredDocument = TemplateStructuredDocument(getParser(), TemplateVersionExhibitor.get) 16 | 17 | // A reparser that always reparses the whole document 18 | val reparser = new XMLStructuredDocumentReParser { 19 | override protected def findDirtyEnd(end: Int): IStructuredDocumentRegion = { 20 | val result = fStructuredDocument.getLastStructuredDocumentRegion() 21 | if (result != null) fStructuredDocument.setCachedDocumentRegion(result) 22 | dirtyEnd = result 23 | dirtyEnd 24 | } 25 | 26 | override protected def findDirtyStart(start: Int): Unit = { 27 | val result = fStructuredDocument.getFirstStructuredDocumentRegion() 28 | if (result != null) fStructuredDocument.setCachedDocumentRegion(result) 29 | dirtyStart = result 30 | } 31 | } 32 | 33 | structuredDocument.delegate.setReParser(reparser) 34 | 35 | // TODO - set the default embedded type content type handler.. whatever that means. 36 | // I don't believe we'll ever need to do that, but if it comes up in the future, this is the place to do it. 37 | structuredDocument 38 | } 39 | 40 | override def newInstance() = new TemplateDocumentLoader 41 | 42 | override def getParser(): RegionParser = new TemplateRegionParser 43 | 44 | override val getDefaultDocumentPartitioner = new TemplateStructuredTextPartitioner 45 | } 46 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/model/TemplateModelHandler.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.model 2 | 3 | import org.eclipse.wst.html.core.internal.encoding.HTMLDocumentCharsetDetector 4 | import org.eclipse.wst.sse.core.internal.document.IDocumentCharsetDetector 5 | import org.eclipse.wst.sse.core.internal.document.IDocumentLoader 6 | import org.eclipse.wst.sse.core.internal.ltk.modelhandler.AbstractModelHandler 7 | import org.eclipse.wst.sse.core.internal.provisional.IModelLoader 8 | 9 | object TemplateModelHandler { 10 | val AssociatedContentTypeID = "org.scalaide.play2.templateSource" 11 | val ModelHandlerID = "org.scalaide.play2.templateModelHandler" 12 | } 13 | 14 | class TemplateModelHandler extends AbstractModelHandler() { 15 | setId(TemplateModelHandler.ModelHandlerID) 16 | setAssociatedContentTypeId(TemplateModelHandler.AssociatedContentTypeID) 17 | 18 | // Perhaps at some point it would be beneficial to have our own documentcharsetdetector. 19 | // At the moment, I don't when there would be a difference between html and template files. 20 | override def getEncodingDetector(): IDocumentCharsetDetector = new HTMLDocumentCharsetDetector 21 | override def getDocumentLoader(): IDocumentLoader = new TemplateDocumentLoader 22 | override def getModelLoader(): IModelLoader = new TemplateModelLoader 23 | } 24 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/model/TemplateStructuredModel.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.model 2 | 3 | import org.eclipse.wst.html.core.internal.document.DOMStyleModelImpl 4 | import org.eclipse.wst.html.core.internal.encoding.HTMLModelLoader 5 | import org.eclipse.wst.sse.core.internal.document.IDocumentLoader 6 | import org.eclipse.wst.sse.core.internal.provisional.IModelLoader 7 | import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel 8 | 9 | // This class (and the inner classes) will need to be overhauled when adding HTMLValidator support 10 | class TemplateStructuredModel extends DOMStyleModelImpl { 11 | import org.eclipse.wst.xml.core.internal.document.DOMModelImpl 12 | import org.eclipse.wst.xml.core.internal.document.XMLModelParser 13 | import org.eclipse.wst.xml.core.internal.document.XMLModelUpdater 14 | 15 | class NestedDOMModelParser(model: DOMModelImpl) extends XMLModelParser(model) 16 | class NestedDOMModelUpdater(model: DOMModelImpl) extends XMLModelUpdater(model) 17 | override def createModelParser() = new NestedDOMModelParser(this) 18 | override def createModelUpdater() = new NestedDOMModelUpdater(this) 19 | } 20 | 21 | class TemplateModelLoader extends HTMLModelLoader { 22 | override def getDocumentLoader(): IDocumentLoader = new TemplateDocumentLoader 23 | override def newModel(): IStructuredModel = new TemplateStructuredModel 24 | override def newInstance(): IModelLoader = new TemplateModelLoader 25 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/style/ScalaLineStyleProvider.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.style 2 | 3 | import org.eclipse.jface.preference.IPreferenceStore 4 | import org.eclipse.wst.html.ui.internal.style.LineStyleProviderForHTML 5 | import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion 6 | import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider 7 | import org.scalaide.play2.templateeditor.sse.lexical.TemplateTextRegion 8 | 9 | class ScalaLineStyleProvider(prefStore: IPreferenceStore) extends LineStyleProviderForHTML with LineStyleProvider { 10 | 11 | protected override def getAttributeFor(region: ITextRegion) = { 12 | region match { 13 | case scalaRegion: TemplateTextRegion => { 14 | scalaRegion.syntaxClass.getTextAttribute(getColorPreferences) 15 | } 16 | case _ => super.getAttributeFor(region) 17 | } 18 | } 19 | 20 | protected override def getColorPreferences() = prefStore 21 | } 22 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/templateeditor/sse/validation/ScalaSourceValidator.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.templateeditor.sse.validation 2 | 3 | import scala.util.Try 4 | import org.eclipse.core.resources.IMarker 5 | import org.eclipse.core.resources.IResource 6 | import org.eclipse.core.resources.ResourcesPlugin 7 | import org.eclipse.core.runtime.Path 8 | import org.eclipse.jdt.core.IJavaModelMarker 9 | import org.eclipse.wst.sse.core.StructuredModelManager 10 | import org.eclipse.wst.validation.internal.provisional.core.IReporter 11 | import org.eclipse.wst.validation.internal.provisional.core.IValidationContext 12 | import org.eclipse.wst.validation.internal.provisional.core.IValidator 13 | import org.scalaide.play2.templateeditor.TemplateCompilationUnitProvider 14 | 15 | 16 | class ScalaSourceValidator extends IValidator { 17 | 18 | /* IValidator methods */ 19 | 20 | def cleanup(report: IReporter) = {} 21 | 22 | def validate(helper: IValidationContext, reporter: IReporter) = { 23 | 24 | val wsroot = ResourcesPlugin.getWorkspace().getRoot() 25 | for { 26 | uri <- helper.getURIs() 27 | if !reporter.isCancelled() 28 | currentFile <- Option(wsroot.getFile(new Path(uri))) 29 | if currentFile.exists() 30 | model <- Try(StructuredModelManager.getModelManager().getModelForRead(currentFile)) 31 | }{ 32 | try { 33 | val markerType = IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER 34 | for { 35 | markers <- Try(currentFile.findMarkers(markerType, true, IResource.DEPTH_ONE)) 36 | marker <- markers 37 | } marker.delete() 38 | 39 | val doc = model.getStructuredDocument() 40 | val compilationUnit = new TemplateCompilationUnitProvider(false).fromFileAndDocument(currentFile, doc) 41 | for (error <- compilationUnit.forceReconcile()) { 42 | val (priority, severity) = 43 | if (error.isError()) (IMarker.PRIORITY_HIGH, IMarker.SEVERITY_ERROR) 44 | else if (error.isWarning()) (IMarker.PRIORITY_NORMAL, IMarker.SEVERITY_WARNING) 45 | else (IMarker.PRIORITY_LOW, IMarker.SEVERITY_INFO) 46 | 47 | val marker = currentFile.createMarker(markerType) 48 | marker.setAttribute(IMarker.LINE_NUMBER, doc.getLineOfOffset(error.getSourceStart()) + 1) 49 | marker.setAttribute(IMarker.CHAR_START, error.getSourceStart()) 50 | marker.setAttribute(IMarker.CHAR_END, error.getSourceStart() + (error.getSourceEnd() - error.getSourceStart() + 1)) 51 | marker.setAttribute(IMarker.MESSAGE, error.getMessage()) 52 | marker.setAttribute(IMarker.USER_EDITABLE, java.lang.Boolean.FALSE) 53 | marker.setAttribute(IMarker.PRIORITY, priority) 54 | marker.setAttribute(IMarker.SEVERITY, severity) 55 | } 56 | } 57 | finally { 58 | model.releaseFromRead() 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/util/Debugger.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.util 2 | 3 | import javax.swing.JFrame 4 | 5 | object Debugger { 6 | def show(message: String) { 7 | new JFrame(message){ 8 | setVisible(true) 9 | setSize(800, 100) 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/util/Images.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.util 2 | 3 | import org.scalaide.play2.PlayPlugin 4 | import org.eclipse.jface.resource.ImageDescriptor 5 | 6 | object Images { 7 | final val ROUTES_ICON = "routes.icon" 8 | final val HTTP_METHODS_ICON = "web.icon" 9 | final val URL_ICON = "url.icon" 10 | val ROUTES_ICON_DESCRIPTOR: ImageDescriptor = PlayPlugin.getImageDescriptor("icons/routes.png") 11 | val HTTP_METHODS_ICON_DESCRIPTOR: ImageDescriptor = PlayPlugin.getImageDescriptor("icons/web.png") 12 | val URL_ICON_DESCRIPTOR: ImageDescriptor = PlayPlugin.getImageDescriptor("icons/pin.png") 13 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/util/Play2PropertyTester.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.util 2 | 3 | import org.eclipse.core.expressions.PropertyTester 4 | import org.eclipse.core.resources.IProject 5 | import org.scalaide.play2.PlayPlugin 6 | import org.eclipse.jdt.core.IJavaProject 7 | 8 | object Play2PropertyTester { 9 | final val IsPlayProject = "isPlay2Project" 10 | } 11 | 12 | /** Eclipse property tester. Can check if a project is a play2 project. 13 | */ 14 | class Play2PropertyTester() extends PropertyTester { 15 | 16 | // from IPropertyTester 17 | 18 | override def test(receiver: Any, property: String, args: Array[Object], expectedValue: Any): Boolean = { 19 | import Play2PropertyTester._ 20 | 21 | property match { 22 | case IsPlayProject => 23 | receiver match { 24 | case project: IProject => 25 | PlayPlugin.instance().asPlayProject(project).isDefined 26 | case project: IJavaProject => 27 | PlayPlugin.instance().asPlayProject(project.getProject()).isDefined 28 | case _ => 29 | false 30 | } 31 | case _ => 32 | false 33 | } 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/util/StoredEditorUtils.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.util 2 | 3 | import org.eclipse.jface.text.TextViewer 4 | import org.scalaide.play2.templateeditor.AbstractTemplateEditor 5 | import org.eclipse.jface.text.ITextViewer 6 | import org.eclipse.core.resources.IFile 7 | import org.eclipse.ui.IFileEditorInput 8 | import org.eclipse.jface.text.source.ISourceViewer 9 | 10 | object StoredEditorUtils { 11 | 12 | def getFileOfViewer(viewer: ITextViewer): Option[IFile] = { 13 | getEditorOfViewer(viewer).map(_.getEditorInput).collect{ 14 | case fileEditorInput: IFileEditorInput => 15 | fileEditorInput.getFile 16 | } 17 | } 18 | 19 | def getEditorOfViewer(viewer: ITextViewer): Option[AbstractTemplateEditor] = 20 | viewer match { 21 | case textViewer: TextViewer => 22 | Option(textViewer.getData("scalaide.play.editor").asInstanceOf[AbstractTemplateEditor]) 23 | case _ => 24 | None 25 | } 26 | 27 | def storeEditorInViewer(sourceViewer: ISourceViewer, editor: AbstractTemplateEditor) { 28 | sourceViewer match { 29 | case tv: TextViewer => 30 | tv.setData("scalaide.play.editor", editor) 31 | case _ => 32 | } 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/util/SyncedScopedPreferenceStore.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.util 2 | 3 | import org.eclipse.core.resources.IProject 4 | import org.eclipse.core.resources.ProjectScope 5 | import org.eclipse.ui.preferences.ScopedPreferenceStore 6 | 7 | class SyncedScopedPreferenceStore(project: IProject, pluginId: String) { 8 | 9 | private val preferenceStore = new ScopedPreferenceStore(new ProjectScope(project), pluginId) 10 | 11 | def getString(name: String): String = { 12 | preferenceStore.synchronized { 13 | preferenceStore.getString(name) 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/wizards/NewTemplateWizard.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.wizards 2 | 3 | import org.eclipse.jface.viewers.IStructuredSelection 4 | import org.eclipse.jface.wizard.Wizard 5 | import org.eclipse.ui.INewWizard 6 | import org.eclipse.ui.IWorkbench 7 | import org.eclipse.ui.PartInitException 8 | import org.eclipse.ui.PlatformUI 9 | import org.eclipse.ui.ide.IDE 10 | import org.scalaide.logging.HasLogger 11 | import org.scalaide.util.ui.DisplayThread 12 | 13 | /** 14 | * A wizard to create a new Play template file. 15 | */ 16 | class NewTemplateWizard extends Wizard with INewWizard with HasLogger { 17 | 18 | // from org.eclipse.jface.wizard.Wizard 19 | 20 | override def performFinish(): Boolean = { 21 | val file = newFileWizardPage.createNewFile() 22 | 23 | if (file != null) { 24 | // if it worked, open the file 25 | DisplayThread.asyncExec { 26 | val page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() 27 | try { 28 | IDE.openEditor(page, file, true) 29 | } catch { 30 | case e: PartInitException => eclipseLog.error("Failed to initialize editor for file "+ file.getName()) 31 | } 32 | } 33 | true 34 | } else { 35 | false 36 | } 37 | } 38 | 39 | override def addPages() { 40 | newFileWizardPage = new NewTemplateWizardPage(selection) 41 | addPage(newFileWizardPage) 42 | } 43 | 44 | // from org.eclipse.ui.INewWizard 45 | 46 | override def init(workbench: IWorkbench, selection: IStructuredSelection) { 47 | this.selection = selection 48 | } 49 | 50 | // ------ 51 | 52 | // set the dialog values 53 | setWindowTitle("New Play Template") 54 | 55 | /** 56 | * The wizard page 57 | */ 58 | private var newFileWizardPage: NewTemplateWizardPage = _ 59 | 60 | /** 61 | * The selection at the initialization of the wizard 62 | */ 63 | private var selection: IStructuredSelection = _ 64 | 65 | } -------------------------------------------------------------------------------- /org.scala-ide.play2/src/org/scalaide/play2/wizards/NewTemplateWizardPage.scala: -------------------------------------------------------------------------------- 1 | package org.scalaide.play2.wizards 2 | 3 | import java.io.ByteArrayInputStream 4 | import java.io.InputStream 5 | import org.eclipse.core.runtime.IStatus 6 | import org.eclipse.core.runtime.Status 7 | import org.eclipse.jface.viewers.IStructuredSelection 8 | import org.eclipse.swt.widgets.Composite 9 | import org.eclipse.ui.dialogs.WizardNewFileCreationPage 10 | import org.scalaide.play2.PlayPlugin 11 | 12 | /** 13 | * Wizard page based of the new file creation page from the framework. 14 | * The advanced section has be removed. 15 | */ 16 | class NewTemplateWizardPage(selection: IStructuredSelection) extends WizardNewFileCreationPage("main", selection) { 17 | 18 | // from org.eclipse.ui.dialogs.WizardNewFileCreationPage 19 | 20 | override def createAdvancedControls(parent: Composite) { 21 | // do nothing, we don't want the 'advanced' section 22 | } 23 | 24 | override def createLinkTarget() { 25 | // do nothing, we don't have this section 26 | } 27 | 28 | override def getInitialContents(): InputStream = { 29 | new ByteArrayInputStream( 30 | """@* %s Template File *@ 31 | @(param: Any) 32 | """ 33 | .format(objectName).getBytes()) 34 | } 35 | 36 | override def validateLinkedResource(): IStatus = { 37 | // do nothing, we don't have this section 38 | Status.OK_STATUS 39 | } 40 | 41 | override def validatePage(): Boolean = { 42 | if (super.validatePage()) { 43 | if (validateIdentifier) { 44 | true 45 | } else { 46 | setErrorMessage("Invalid template name") 47 | false 48 | } 49 | } else { 50 | false 51 | } 52 | } 53 | 54 | // ------ 55 | 56 | // set the page values 57 | setTitle("Play Template") 58 | setDescription("Create a new Play Template") 59 | setFileExtension(PlayPlugin.TemplateExtension) 60 | 61 | /** 62 | * Return the name of the object to be created, or empty if not available. 63 | */ 64 | def objectName = { 65 | val fileName = getFileName() 66 | val extenstionLength = ("." + PlayPlugin.TemplateExtension).length() 67 | if (fileName.length > extenstionLength) { 68 | fileName.substring(0, fileName.length() - extenstionLength) 69 | } else { 70 | "" 71 | } 72 | } 73 | 74 | /** 75 | * check if the object name is a valid identifier. 76 | * TODO: switch to Scala identifier check. Right now it is checking for a Java identifier 77 | */ 78 | def validateIdentifier: Boolean = { 79 | objectName.toList match { 80 | case Nil => 81 | true 82 | case head :: Nil => 83 | Character.isJavaIdentifierStart(head) 84 | case head :: tail => 85 | Character.isJavaIdentifierStart(head) && tail.foldLeft(true)((b: Boolean, c: Char) => b && Character.isJavaIdentifierPart(c)) 86 | } 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 3.0 7 | 8 | 9 | 10 | org.scala-ide 11 | plugin-profiles 12 | 1.0.14 13 | 14 | 15 | org.scala-ide 16 | org.scala-ide.play2.build 17 | 0.11.0-SNAPSHOT 18 | Play 2 Support for Scala IDE 19 | pom 20 | 21 | 22 | org.scala-ide.play2 23 | org.scala-ide.play2.templates 24 | org.scala-ide.play2.tests 25 | org.scala-ide.play2.feature 26 | org.scala-ide.play2.source.feature 27 | org.scala-ide.play2.update-site 28 | 29 | 30 | 31 | 2.12 32 | 33 | twirl-compiler_${scala.binary.version} 34 | 1.2.0.v20160929-1449 35 | twirl-parser_${scala.binary.version} 36 | 1.3.0 37 | 38 | 39 | 40 | 41 | 42 | com.typesafe.play 43 | ${twirl-compiler.artifactId} 44 | ${twirl.version} 45 | 46 | 47 | com.typesafe.play 48 | ${twirl-parser.artifactId} 49 | ${twirl.version} 50 | 51 | 52 | 53 | 54 | --------------------------------------------------------------------------------