Skip to content

Commit

Permalink
Fixes scala-ide#93 - Editor cut-off value is now applied per-evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
dotta committed Oct 16, 2012
1 parent c00e791 commit df4eada
Showing 1 changed file with 42 additions and 18 deletions.
Expand Up @@ -2,28 +2,29 @@ package org.scalaide.worksheet.runtime

import java.io.Writer

import scala.actors.{ Actor, DaemonActor, TIMEOUT }
import scala.actors.{Actor, DaemonActor, TIMEOUT}
import scala.collection.mutable.LinkedHashMap
import scala.collection.mutable.ListBuffer
import scala.tools.eclipse.logging.HasLogger

import org.scalaide.worksheet.editor.DocumentHolder
import org.scalaide.worksheet.text.{ Mixer, SourceInserter }

object IncrementalDocumentMixer {
def apply(editor: DocumentHolder, source: Writer, maxOutput: Int = MaximumOutputChars): Actor = {
def apply(editor: DocumentHolder, source: Writer, maxOutput: Int): Actor = {
val incrementalMixer = new IncrementalDocumentMixer(editor, source, maxOutput)
incrementalMixer.start()
incrementalMixer
}

final val RefreshDocumentTimeout = 200
final val MaximumOutputChars = 100
private final val RefreshDocumentTimeout = 200

/** How many ticks should pass with output not changing before adding a spinner? */
final val InfiniteLoopTicks = 1000 / RefreshDocumentTimeout // 1 sec
private final val InfiniteLoopTicks = 1000 / RefreshDocumentTimeout // 1 sec
}

private class IncrementalDocumentMixer private (editor: DocumentHolder, source: Writer, val maximumOutputSize: Int) extends DaemonActor with HasLogger {
import IncrementalDocumentMixer.{ RefreshDocumentTimeout, InfiniteLoopTicks }
import IncrementalDocumentMixer.{ RefreshDocumentTimeout, InfiniteLoopTicks}

private val originalContent = editor.getContents
private val stripped = SourceInserter.stripRight(editor.getContents.toCharArray)
Expand All @@ -45,7 +46,7 @@ private class IncrementalDocumentMixer private (editor: DocumentHolder, source:

private def updateDocument(newText: String): Unit = {
if (newText.length > 0) {
val (mixed, lastInsertion) = mixer.mix(stripped, showLongRunning(pruneOutput(newText)).toCharArray())
val (mixed, lastInsertion) = mixer.mix(stripped, showLongRunning(pruneOutputPerEvaluation(newText)).toCharArray())
editor.replaceWith(mixed.mkString, lastInsertion)
}
}
Expand Down Expand Up @@ -73,17 +74,40 @@ private class IncrementalDocumentMixer private (editor: DocumentHolder, source:
}
}

def pruneOutput(newText: String): String = {
if (newText.length() > maximumOutputSize) {
val lastNL = newText.indexOf('\n', maximumOutputSize)
val endPos = if (lastNL == -1) newText.length else lastNL
val displayableText = newText.substring(0, endPos)
val suffix = if (displayableText.last == '\n') "" else "\n"
val lastLine = displayableText.lines.toSeq.last
val offset = lastLine.substring(0, lastLine.indexOf(' ', 0))
logger.debug("Cutting off large output at position: " + offset)
displayableText + suffix + offset + " Output exceeds cutoff limit. "
} else newText
def pruneOutputPerEvaluation(newText: String): String = {
// Extracts the offset prefixed to each line in the evaluation output
object Offset {
private val offsetExtractor = """^(\d*)""".r
def unapply(line: String): Option[String] = offsetExtractor.findFirstIn(line)
}
// Groups together `lines` that share the same offset
def groupLinesByOffset(lines: List[String], acc: LinkedHashMap[String, ListBuffer[String]]): LinkedHashMap[String, ListBuffer[String]] = lines match {
case Nil => acc
case line :: rest =>
groupLinesByOffset(rest,
line match {
case Offset(offset) =>
acc.get(offset) match {
case None => acc += (offset -> ListBuffer(line))
case Some(result) => acc += ((offset, result += line))
}

case _ =>
logger.error("Discarded evaluation result, this is a bug. Please open a ticket and make sure to provide the worksheet source that generated this warning.")
acc
})
}

val lines = newText.split('\n')
val linesByOffset = groupLinesByOffset(lines.toList, LinkedHashMap.empty)

val evaluationResults = for((_, evaluationOutputs) <- linesByOffset) yield {
val evaluationResult = evaluationOutputs.mkString("\n")
(if(evaluationResult.length <= maximumOutputSize) evaluationResult
else evaluationResult.take(maximumOutputSize) + " Output exceeds cutoff limit. ")
}

evaluationResults.mkString("\n")
}

override def toString: String = "IncrementalDocumentMixer <actor>"
Expand Down

0 comments on commit df4eada

Please sign in to comment.