diff --git a/modules/scala/jupyter-api/src/main/scala/almond/api/JupyterApi.scala b/modules/scala/jupyter-api/src/main/scala/almond/api/JupyterApi.scala index 177c5572e..f34b827f2 100644 --- a/modules/scala/jupyter-api/src/main/scala/almond/api/JupyterApi.scala +++ b/modules/scala/jupyter-api/src/main/scala/almond/api/JupyterApi.scala @@ -17,6 +17,9 @@ abstract class JupyterApi { api => def stdinOpt(prompt: String = "", password: Boolean = false): Option[String] + def silent(s: Boolean): Unit = {} + def silent: Boolean = false + protected implicit def changingPublish: OutputHandler = new almond.interpreter.api.OutputHandler.OnlyUpdateVia(commHandler) diff --git a/modules/scala/scala-interpreter/src/main/scala/almond/Execute.scala b/modules/scala/scala-interpreter/src/main/scala/almond/Execute.scala index 56c628b61..3d3a169a9 100644 --- a/modules/scala/scala-interpreter/src/main/scala/almond/Execute.scala +++ b/modules/scala/scala-interpreter/src/main/scala/almond/Execute.scala @@ -30,7 +30,8 @@ final class Execute( storage: Storage, logCtx: LoggerContext, updateBackgroundVariablesEcOpt: Option[ExecutionContext], - commHandlerOpt: => Option[CommHandler] + commHandlerOpt: => Option[CommHandler], + silent: Ref[Boolean] ) { private val log = logCtx(getClass) @@ -223,7 +224,7 @@ final class Execute( resultOutput.clear() resultVariables.clear() log.debug(s"Compiling / evaluating $code ($stmts)") - val r = ammInterp.processLine(code, stmts, currentLine0, silent = false, incrementLine = () => currentLine0 += 1) + val r = ammInterp.processLine(code, stmts, currentLine0, silent = silent(), incrementLine = () => currentLine0 += 1) log.debug(s"Handling output of $code") Repl.handleOutput(ammInterp, r) diff --git a/modules/scala/scala-interpreter/src/main/scala/almond/JupyterApiImpl.scala b/modules/scala/scala-interpreter/src/main/scala/almond/JupyterApiImpl.scala index 2b323dc70..60a47a8c6 100644 --- a/modules/scala/scala-interpreter/src/main/scala/almond/JupyterApiImpl.scala +++ b/modules/scala/scala-interpreter/src/main/scala/almond/JupyterApiImpl.scala @@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets import almond.api.{FullJupyterApi, JupyterApi} import almond.internals.HtmlAnsiOutputStream import almond.interpreter.api.CommHandler +import ammonite.util.Ref import pprint.{TPrint, TPrintColors} import scala.concurrent.Await @@ -16,7 +17,8 @@ import scala.reflect.ClassTag final class JupyterApiImpl( execute: Execute, commHandlerOpt: => Option[CommHandler], - replApi: ReplApiImpl + replApi: ReplApiImpl, + silent0: Ref[Boolean] ) extends FullJupyterApi { protected def printOnChange[T]( @@ -34,6 +36,9 @@ final class JupyterApiImpl( replApi.Internal.print(value, ident, custom)(tprint, tcolors, classTagT) } + override def silent(s: Boolean): Unit = silent0.update(s) + override def silent: Boolean = silent0.apply() + protected def ansiTextToHtml(text: String): String = { val baos = new ByteArrayOutputStream val haos = new HtmlAnsiOutputStream(baos) diff --git a/modules/scala/scala-interpreter/src/main/scala/almond/ScalaInterpreter.scala b/modules/scala/scala-interpreter/src/main/scala/almond/ScalaInterpreter.scala index df02af5eb..7a08dfff8 100644 --- a/modules/scala/scala-interpreter/src/main/scala/almond/ScalaInterpreter.scala +++ b/modules/scala/scala-interpreter/src/main/scala/almond/ScalaInterpreter.scala @@ -38,6 +38,8 @@ final class ScalaInterpreter( private val colors0: Ref[Colors] = Ref(params.initialColors) + private val silent0: Ref[Boolean] = Ref(false) + private var commHandlerOpt = Option.empty[CommHandler] private val storage = @@ -51,7 +53,8 @@ final class ScalaInterpreter( storage, logCtx, params.updateBackgroundVariablesEcOpt, - commHandlerOpt + commHandlerOpt, + silent0 ) @@ -69,7 +72,7 @@ final class ScalaInterpreter( ) val jupyterApi = - new JupyterApiImpl(execute0, commHandlerOpt, replApi) + new JupyterApiImpl(execute0, commHandlerOpt, replApi, silent0) for (ec <- params.updateBackgroundVariablesEcOpt) UpdatableFuture.setup(replApi, jupyterApi, ec) diff --git a/modules/scala/scala-interpreter/src/test/scala/almond/ScalaInterpreterTests.scala b/modules/scala/scala-interpreter/src/test/scala/almond/ScalaInterpreterTests.scala index 63d947852..a06793b42 100644 --- a/modules/scala/scala-interpreter/src/test/scala/almond/ScalaInterpreterTests.scala +++ b/modules/scala/scala-interpreter/src/test/scala/almond/ScalaInterpreterTests.scala @@ -15,7 +15,7 @@ object ScalaInterpreterTests extends TestSuite { private val sbv = scala.util.Properties.versionNumberString.split('.').take(2).mkString(".") - private val interpreter: Interpreter = + private def newInterpreter: Interpreter = new ScalaInterpreter( params = ScalaInterpreterParams( initialColors = Colors.BlackWhite, @@ -31,6 +31,8 @@ object ScalaInterpreterTests extends TestSuite { logCtx = logCtx ) + private val interpreter: Interpreter = newInterpreter + private object Predef { private def predefPath(name: String): Path = Paths.get(getClass.getResource(s"/test-predefs/$name.sc").toURI) @@ -237,6 +239,103 @@ object ScalaInterpreterTests extends TestSuite { "exception" - Predef.exception(fileBased = true) } + "silent" - { + "defaults false" - { + val code = "val silent = kernel.silent" + val res = newInterpreter.execute(code) + val expectedRes = ExecuteResult.Success(DisplayData.text("silent: Boolean = false")) + assert(res == expectedRes) + } + "can be set to true" - { + val code = + """ + | val silentBefore = kernel.silent + | kernel.silent(true) + | val silentAfter = kernel.silent + |""".stripMargin + val res = newInterpreter.execute(code) + val expectedRes = ExecuteResult.Success(DisplayData.text( + """silentBefore: Boolean = false + |silentAfter: Boolean = true""".stripMargin)) + assert(res == expectedRes) + } + "can be set to false" - { + val code = + """ + | kernel.silent(true) + | val silentBefore = kernel.silent + | kernel.silent(false) + | val silentAfter = kernel.silent + |""".stripMargin + val res = newInterpreter.execute(code) + val expectedRes = ExecuteResult.Success(DisplayData.text( + """silentBefore: Boolean = true + |silentAfter: Boolean = false""".stripMargin)) + assert(res == expectedRes) + } + "affects subsequent calls to execute when enabled" - { + val code0 = + """ + | kernel.silent(true) + | val noEffectInSameExecute = kernel.silent + |""".stripMargin + val code1 = + """ + | val effectInNextExecute = 0 + |""".stripMargin + val code2 = + """ + | val effectInNextExecuteAgain = 0 + |""".stripMargin + val i = newInterpreter + val res0 = i.execute(code0) + val res1 = i.execute(code1) + val res2 = i.execute(code2) + val expectedRes0 = ExecuteResult.Success(DisplayData.text( + "noEffectInSameExecute: Boolean = true")) + val expectedRes1 = ExecuteResult.Success(DisplayData.empty) + val expectedRes2 = ExecuteResult.Success(DisplayData.empty) + assert(res0 == expectedRes0) + assert(res1 == expectedRes1) + assert(res2 == expectedRes2) + } + + "affects subsequent calls to execute when disabled" - { + val code0 = "kernel.silent(true)" + val code1 = + """ + | kernel.silent(false) + | val noEffectInSameExecute = kernel.silent + |""".stripMargin + val code2 = + """ + | val effectInNextExecute = kernel.silent + |""".stripMargin + val code3 = + """ + | val effectInNextExecuteAgain = kernel.silent + |""".stripMargin + + val i = newInterpreter + val res0 = i.execute(code0) + val res1 = i.execute(code1) + val res2 = i.execute(code2) + val res3 = i.execute(code3) + + val expectedRes0 = ExecuteResult.Success(DisplayData.empty) + val expectedRes1 = ExecuteResult.Success(DisplayData.empty) + val expectedRes2 = ExecuteResult.Success(DisplayData.text( + "effectInNextExecute: Boolean = false")) + val expectedRes3 = ExecuteResult.Success(DisplayData.text( + "effectInNextExecuteAgain: Boolean = false")) + + assert(res0 == expectedRes0) + assert(res1 == expectedRes1) + assert(res2 == expectedRes2) + assert(res3 == expectedRes3) + } + } + "dependencies" - { "auto dependency" - { "example" - {