Permalink
Browse files

Re #1000764. Refreshing presentation compiler data

Play 2.0 works fine in Scala IDE, except for the fact that information in the presentation compiler
about file changed in the filesystem is not correctly updated.
This change detect those changes, and trigger the presentation compiler.

Cherry-picked from 795e18f
  • Loading branch information...
1 parent ff4792f commit e8eb06d1da33f8378eb1d31095dd9d83e60f4756 @skyluc skyluc committed Nov 23, 2011
@@ -31,6 +31,9 @@ import org.eclipse.core.resources.IResourceDelta
import scala.tools.eclipse.util.HasLogger
import org.osgi.framework.Bundle
import scala.tools.eclipse.util.Utils
+import org.eclipse.jdt.core.ICompilationUnit
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.eclipse.util.EclipseResource
object ScalaPlugin {
var plugin: ScalaPlugin = _
@@ -244,6 +247,7 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
// process deleted files
val buff = new ListBuffer[ScalaSourceFile]
+ val changed = new ListBuffer[ICompilationUnit]
val projectsToReset = new mutable.HashSet[ScalaProject]
def findRemovedSources(delta: IJavaElementDelta) {
@@ -274,6 +278,12 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
} else
true
+ // TODO: the check should be done with isInstanceOf[ScalaSourceFile] instead of
+ // endsWith(scalaFileExtn), but it is not working for Play 2.0 because of #1000434
+ case COMPILATION_UNIT if isChanged && elem.getResource.getName.endsWith(scalaFileExtn) =>
+ // marked the changed scala files to be refreshed in the presentation compiler if needed
+ changed += elem.asInstanceOf[ICompilationUnit]
+ false
case COMPILATION_UNIT if elem.isInstanceOf[ScalaSourceFile] && isRemoved =>
buff += elem.asInstanceOf[ScalaSourceFile]
false
@@ -291,6 +301,17 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
}
findRemovedSources(event.getDelta)
+ // ask for the changed scala files to be refreshed in each project presentation compiler if needed
+ if (changed.nonEmpty) {
+ changed.toList groupBy(_.getJavaProject.getProject) foreach {
+ case (project, units) =>
+ asScalaProject(project) foreach { p =>
+ if (project.isOpen && !projectsToReset(p)) {
+ p.refreshChangedFiles(units.map(_.getResource.asInstanceOf[IFile]))
+ }
+ }
+ }
+ }
projectsToReset.foreach(_.resetPresentationCompiler)
if(buff.nonEmpty) {
@@ -10,7 +10,7 @@ import scala.collection.mutable
import java.io.File.pathSeparator
import org.eclipse.core.resources.{ IContainer, IFile, IFolder, IMarker, IProject, IResource, IResourceProxy, IResourceProxyVisitor }
import org.eclipse.core.runtime.{ FileLocator, IPath, IProgressMonitor, Path, SubMonitor }
-import org.eclipse.jdt.core.{ IClasspathEntry, IJavaProject, JavaCore }
+import org.eclipse.jdt.core.{ IClasspathEntry, IJavaProject, JavaCore, ICompilationUnit }
import org.eclipse.jdt.core.compiler.IProblem
import org.eclipse.jdt.internal.core.JavaProject
import org.eclipse.jdt.internal.core.util.Util
@@ -36,6 +36,9 @@ import org.eclipse.core.runtime.Status
import scala.tools.eclipse.util.Utils
import org.eclipse.jdt.core.IJavaModelMarker
import scala.tools.eclipse.util.FileUtils
+import scala.tools.nsc.util.BatchSourceFile
+import java.io.InputStream
+import java.io.InputStreamReader
trait BuildSuccessListener {
def buildSuccessful(): Unit
@@ -762,4 +765,47 @@ class ScalaProject private (val underlying: IProject) extends HasLogger {
def shutDownPresentationCompiler() {
presentationCompiler.invalidate()
}
+
+ /**
+ * Return the full content of the given file in a Char array.
+ *
+ * Need to replace this with an utility method. I cannot believe it doesn't
+ * exist somewhere else.
+ */
+ private def readFully(file: IFile): Array[Char] = {
+ val reader= new InputStreamReader(file.getContents, file.getCharset())
+ val buf= new ListBuffer[Char]
+ var c= reader.read
+ while (c >= 0) {
+ buf+= c.asInstanceOf[Char]
+ c= reader.read
+ }
+ buf.toArray
+ }
+
+ /**
+ * Tell the presentation compiler to refresh the given files,
+ * if they are not managed by the presentation compiler already.
+ */
+ def refreshChangedFiles(files: List[IFile]) {
+ // transform to batch source files
+ val abstractfiles= files.map(file => new BatchSourceFile(EclipseResource(file), readFully(file)))
+
+ withPresentationCompiler {compiler =>
+ import compiler._
+ // only the files not already managed should be refreshed
+ val notLoadedFiles= abstractfiles.filter(compiler.getUnitOf(_).isEmpty)
+
+ notLoadedFiles.foreach(file => {
+ // call askParsedEntered to force the refresh without loading the file
+ val r = new Response[Tree]
+ compiler.askParsedEntered(file, false, r)
+ r.get.left
+ })
+
+ // reconcile the opened editors if some files have been refreshed
+ if (notLoadedFiles.nonEmpty)
+ compiler.compilationUnits.foreach(_.scheduleReconcile())
+ }(Nil)
+ }
}

0 comments on commit e8eb06d

Please sign in to comment.